]> granicus.if.org Git - clang/commitdiff
Chris Lattner has strong opinions about directory
authorTed Kremenek <kremenek@apple.com>
Thu, 23 Dec 2010 19:38:26 +0000 (19:38 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 23 Dec 2010 19:38:26 +0000 (19:38 +0000)
layout.  :)

Rename the 'EntoSA' directories to 'StaticAnalyzer'.

Internally we will still use the 'ento' namespace
for the analyzer engine (unless there are further
sabre rattlings...).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122514 91177308-0d34-0410-b5e6-96231b3b80d8

255 files changed:
examples/PrintFunctionNames/CMakeLists.txt
examples/clang-interpreter/CMakeLists.txt
examples/clang-interpreter/Makefile
examples/wpa/CMakeLists.txt
examples/wpa/Makefile
include/clang/StaticAnalyzer/AnalysisConsumer.h [moved from include/clang/EntoSA/AnalysisConsumer.h with 100% similarity]
include/clang/StaticAnalyzer/BugReporter/BugReporter.h [moved from include/clang/EntoSA/BugReporter/BugReporter.h with 99% similarity]
include/clang/StaticAnalyzer/BugReporter/BugType.h [moved from include/clang/EntoSA/BugReporter/BugType.h with 97% similarity]
include/clang/StaticAnalyzer/BugReporter/PathDiagnostic.h [moved from include/clang/EntoSA/BugReporter/PathDiagnostic.h with 100% similarity]
include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h [moved from include/clang/EntoSA/Checkers/DereferenceChecker.h with 100% similarity]
include/clang/StaticAnalyzer/Checkers/LocalCheckers.h [moved from include/clang/EntoSA/Checkers/LocalCheckers.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/AnalysisConsumer.h [new file with mode: 0644]
include/clang/StaticAnalyzer/EntoSA/BugReporter/BugReporter.h [new file with mode: 0644]
include/clang/StaticAnalyzer/EntoSA/BugReporter/BugType.h [new file with mode: 0644]
include/clang/StaticAnalyzer/EntoSA/BugReporter/PathDiagnostic.h [new file with mode: 0644]
include/clang/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.h [new file with mode: 0644]
include/clang/StaticAnalyzer/EntoSA/Checkers/LocalCheckers.h [new file with mode: 0644]
include/clang/StaticAnalyzer/EntoSA/FrontendActions.h [moved from include/clang/EntoSA/FrontendActions.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/ManagerRegistry.h [moved from include/clang/EntoSA/ManagerRegistry.h with 96% similarity]
include/clang/StaticAnalyzer/EntoSA/PathDiagnosticClients.h [moved from include/clang/EntoSA/PathDiagnosticClients.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/AnalysisManager.h [moved from include/clang/EntoSA/PathSensitive/AnalysisManager.h with 98% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/BasicValueFactory.h [moved from include/clang/EntoSA/PathSensitive/BasicValueFactory.h with 99% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/BlockCounter.h [moved from include/clang/EntoSA/PathSensitive/BlockCounter.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/Checker.h [moved from include/clang/EntoSA/PathSensitive/Checker.h with 99% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/CheckerHelpers.h [moved from include/clang/EntoSA/PathSensitive/CheckerHelpers.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/CheckerVisitor.def [moved from include/clang/EntoSA/PathSensitive/CheckerVisitor.def with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/CheckerVisitor.h [moved from include/clang/EntoSA/PathSensitive/CheckerVisitor.h with 92% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/ConstraintManager.h [moved from include/clang/EntoSA/PathSensitive/ConstraintManager.h with 97% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/CoreEngine.h [moved from include/clang/EntoSA/PathSensitive/CoreEngine.h with 98% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/Environment.h [moved from include/clang/EntoSA/PathSensitive/Environment.h with 96% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/ExplodedGraph.h [moved from include/clang/EntoSA/PathSensitive/ExplodedGraph.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/ExprEngine.h [moved from include/clang/EntoSA/PathSensitive/ExprEngine.h with 98% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/ExprEngineBuilders.h [moved from include/clang/EntoSA/PathSensitive/ExprEngineBuilders.h with 97% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/GRState.h [moved from include/clang/EntoSA/PathSensitive/GRState.h with 99% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/GRStateTrait.h [moved from include/clang/EntoSA/PathSensitive/GRStateTrait.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/MemRegion.h [moved from include/clang/EntoSA/PathSensitive/MemRegion.h with 99% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/SValBuilder.h [moved from include/clang/EntoSA/PathSensitive/SValBuilder.h with 97% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/SVals.h [moved from include/clang/EntoSA/PathSensitive/SVals.h with 99% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/Store.h [moved from include/clang/EntoSA/PathSensitive/Store.h with 98% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/SubEngine.h [moved from include/clang/EntoSA/PathSensitive/SubEngine.h with 98% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/SummaryManager.h [moved from include/clang/EntoSA/PathSensitive/SummaryManager.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/SymbolManager.h [moved from include/clang/EntoSA/PathSensitive/SymbolManager.h with 100% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/TransferFuncs.h [moved from include/clang/EntoSA/PathSensitive/TransferFuncs.h with 96% similarity]
include/clang/StaticAnalyzer/EntoSA/PathSensitive/WorkList.h [moved from include/clang/EntoSA/PathSensitive/WorkList.h with 97% similarity]
include/clang/StaticAnalyzer/FrontendActions.h [new file with mode: 0644]
include/clang/StaticAnalyzer/ManagerRegistry.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathDiagnosticClients.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/AnalysisManager.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/BlockCounter.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/Checker.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/ConstraintManager.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/CoreEngine.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/Environment.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/GRState.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/GRStateTrait.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/MemRegion.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/SValBuilder.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/SVals.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/Store.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/SubEngine.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/SummaryManager.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/SymbolManager.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h [new file with mode: 0644]
include/clang/StaticAnalyzer/PathSensitive/WorkList.h [new file with mode: 0644]
lib/CMakeLists.txt
lib/FrontendTool/CMakeLists.txt
lib/FrontendTool/ExecuteCompilerInvocation.cpp
lib/Makefile
lib/StaticAnalyzer/AggExprVisitor.cpp [moved from lib/EntoSA/AggExprVisitor.cpp with 97% similarity]
lib/StaticAnalyzer/AnalysisManager.cpp [moved from lib/EntoSA/AnalysisManager.cpp with 94% similarity]
lib/StaticAnalyzer/AnalyzerStatsChecker.cpp [moved from lib/EntoSA/AnalyzerStatsChecker.cpp with 95% similarity]
lib/StaticAnalyzer/BasicConstraintManager.cpp [moved from lib/EntoSA/BasicConstraintManager.cpp with 98% similarity]
lib/StaticAnalyzer/BasicStore.cpp [moved from lib/EntoSA/BasicStore.cpp with 99% similarity]
lib/StaticAnalyzer/BasicValueFactory.cpp [moved from lib/EntoSA/BasicValueFactory.cpp with 99% similarity]
lib/StaticAnalyzer/BlockCounter.cpp [moved from lib/EntoSA/BlockCounter.cpp with 97% similarity]
lib/StaticAnalyzer/BugReporter.cpp [moved from lib/EntoSA/BugReporter.cpp with 99% similarity]
lib/StaticAnalyzer/BugReporterVisitors.cpp [moved from lib/EntoSA/BugReporterVisitors.cpp with 98% similarity]
lib/StaticAnalyzer/CFRefCount.cpp [moved from lib/EntoSA/CFRefCount.cpp with 99% similarity]
lib/StaticAnalyzer/CMakeLists.txt [moved from lib/EntoSA/CMakeLists.txt with 85% similarity]
lib/StaticAnalyzer/CXXExprEngine.cpp [moved from lib/EntoSA/CXXExprEngine.cpp with 99% similarity]
lib/StaticAnalyzer/Checker.cpp [moved from lib/EntoSA/Checker.cpp with 95% similarity]
lib/StaticAnalyzer/CheckerHelpers.cpp [moved from lib/EntoSA/CheckerHelpers.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp [moved from lib/EntoSA/Checkers/AdjustedReturnValueChecker.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp [moved from lib/EntoSA/Checkers/AnalysisConsumer.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp [moved from lib/EntoSA/Checkers/ArrayBoundChecker.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp [moved from lib/EntoSA/Checkers/ArrayBoundCheckerV2.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp [moved from lib/EntoSA/Checkers/AttrNonNullChecker.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp [moved from lib/EntoSA/Checkers/BasicObjCFoundationChecks.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h [moved from lib/EntoSA/Checkers/BasicObjCFoundationChecks.h with 100% similarity]
lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp [moved from lib/EntoSA/Checkers/BuiltinFunctionChecker.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/CMakeLists.txt [moved from lib/EntoSA/Checkers/CMakeLists.txt with 90% similarity]
lib/StaticAnalyzer/Checkers/CStringChecker.cpp [moved from lib/EntoSA/Checkers/CStringChecker.cpp with 99% similarity]
lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp [moved from lib/EntoSA/Checkers/CallAndMessageChecker.cpp with 99% similarity]
lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp [moved from lib/EntoSA/Checkers/CastSizeChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp [moved from lib/EntoSA/Checkers/CastToStructChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/CheckDeadStores.cpp [moved from lib/EntoSA/Checkers/CheckDeadStores.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp [moved from lib/EntoSA/Checkers/CheckObjCDealloc.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp [moved from lib/EntoSA/Checkers/CheckObjCInstMethSignature.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp [moved from lib/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp with 99% similarity]
lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp [moved from lib/EntoSA/Checkers/CheckSizeofPointer.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/ChrootChecker.cpp [moved from lib/EntoSA/Checkers/ChrootChecker.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp [moved from lib/EntoSA/Checkers/DereferenceChecker.cpp with 96% similarity]
lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp [moved from lib/EntoSA/Checkers/DivZeroChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/ExprEngine.cpp [moved from lib/EntoSA/Checkers/ExprEngine.cpp with 99% similarity]
lib/StaticAnalyzer/Checkers/ExprEngineExperimentalChecks.cpp [moved from lib/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp with 96% similarity]
lib/StaticAnalyzer/Checkers/ExprEngineExperimentalChecks.h [moved from lib/EntoSA/Checkers/ExprEngineExperimentalChecks.h with 100% similarity]
lib/StaticAnalyzer/Checkers/ExprEngineInternalChecks.h [moved from lib/EntoSA/Checkers/ExprEngineInternalChecks.h with 100% similarity]
lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp [moved from lib/EntoSA/Checkers/FixedAddressChecker.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/FrontendActions.cpp [moved from lib/EntoSA/Checkers/FrontendActions.cpp with 88% similarity]
lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp [moved from lib/EntoSA/Checkers/IdempotentOperationChecker.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp [moved from lib/EntoSA/Checkers/LLVMConventionsChecker.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp [moved from lib/EntoSA/Checkers/MacOSXAPIChecker.cpp with 96% similarity]
lib/StaticAnalyzer/Checkers/Makefile [moved from lib/EntoSA/Checkers/Makefile with 92% similarity]
lib/StaticAnalyzer/Checkers/MallocChecker.cpp [moved from lib/EntoSA/Checkers/MallocChecker.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp [moved from lib/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp with 93% similarity]
lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp [moved from lib/EntoSA/Checkers/NSErrorChecker.cpp with 96% similarity]
lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp [moved from lib/EntoSA/Checkers/NoReturnFunctionChecker.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp [moved from lib/EntoSA/Checkers/OSAtomicChecker.cpp with 99% similarity]
lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp [moved from lib/EntoSA/Checkers/ObjCAtSyncChecker.cpp with 92% similarity]
lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp [moved from lib/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp with 96% similarity]
lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp [moved from lib/EntoSA/Checkers/PointerArithChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp [moved from lib/EntoSA/Checkers/PointerSubChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp [moved from lib/EntoSA/Checkers/PthreadLockChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp [moved from lib/EntoSA/Checkers/ReturnPointerRangeChecker.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp [moved from lib/EntoSA/Checkers/ReturnUndefChecker.cpp with 91% similarity]
lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp [moved from lib/EntoSA/Checkers/StackAddrLeakChecker.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/StreamChecker.cpp [moved from lib/EntoSA/Checkers/StreamChecker.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp [moved from lib/EntoSA/Checkers/UndefBranchChecker.cpp with 97% similarity]
lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp [moved from lib/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp with 94% similarity]
lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp [moved from lib/EntoSA/Checkers/UndefResultChecker.cpp with 93% similarity]
lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp [moved from lib/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp with 93% similarity]
lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp [moved from lib/EntoSA/Checkers/UndefinedAssignmentChecker.cpp with 95% similarity]
lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp [moved from lib/EntoSA/Checkers/UnixAPIChecker.cpp with 98% similarity]
lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp [moved from lib/EntoSA/Checkers/UnreachableCodeChecker.cpp with 96% similarity]
lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp [moved from lib/EntoSA/Checkers/VLASizeChecker.cpp with 96% similarity]
lib/StaticAnalyzer/CoreEngine.cpp [moved from lib/EntoSA/CoreEngine.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/AggExprVisitor.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/AnalysisManager.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/AnalyzerStatsChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/BasicConstraintManager.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/BasicStore.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/BasicValueFactory.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/BlockCounter.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/BugReporter.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/BugReporterVisitors.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/CFRefCount.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/CMakeLists.txt [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/CXXExprEngine.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/CheckerHelpers.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/Makefile [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/CoreEngine.cpp [new file with mode: 0644]
lib/StaticAnalyzer/EntoSA/Environment.cpp [moved from lib/EntoSA/Environment.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/ExplodedGraph.cpp [moved from lib/EntoSA/ExplodedGraph.cpp with 98% similarity]
lib/StaticAnalyzer/EntoSA/FlatStore.cpp [moved from lib/EntoSA/FlatStore.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/GRState.cpp [moved from lib/EntoSA/GRState.cpp with 98% similarity]
lib/StaticAnalyzer/EntoSA/HTMLDiagnostics.cpp [moved from lib/EntoSA/HTMLDiagnostics.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/Makefile [moved from lib/EntoSA/Makefile with 93% similarity]
lib/StaticAnalyzer/EntoSA/ManagerRegistry.cpp [moved from lib/EntoSA/ManagerRegistry.cpp with 93% similarity]
lib/StaticAnalyzer/EntoSA/MemRegion.cpp [moved from lib/EntoSA/MemRegion.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/PathDiagnostic.cpp [moved from lib/EntoSA/PathDiagnostic.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/PlistDiagnostics.cpp [moved from lib/EntoSA/PlistDiagnostics.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/README.txt [moved from lib/EntoSA/README.txt with 100% similarity]
lib/StaticAnalyzer/EntoSA/RangeConstraintManager.cpp [moved from lib/EntoSA/RangeConstraintManager.cpp with 98% similarity]
lib/StaticAnalyzer/EntoSA/RegionStore.cpp [moved from lib/EntoSA/RegionStore.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/SValBuilder.cpp [moved from lib/EntoSA/SValBuilder.cpp with 97% similarity]
lib/StaticAnalyzer/EntoSA/SVals.cpp [moved from lib/EntoSA/SVals.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/SimpleConstraintManager.cpp [moved from lib/EntoSA/SimpleConstraintManager.cpp with 98% similarity]
lib/StaticAnalyzer/EntoSA/SimpleConstraintManager.h [moved from lib/EntoSA/SimpleConstraintManager.h with 96% similarity]
lib/StaticAnalyzer/EntoSA/SimpleSValBuilder.cpp [moved from lib/EntoSA/SimpleSValBuilder.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/Store.cpp [moved from lib/EntoSA/Store.cpp with 99% similarity]
lib/StaticAnalyzer/EntoSA/SymbolManager.cpp [moved from lib/EntoSA/SymbolManager.cpp with 98% similarity]
lib/StaticAnalyzer/EntoSA/TextPathDiagnostics.cpp [moved from lib/EntoSA/TextPathDiagnostics.cpp with 94% similarity]
lib/StaticAnalyzer/Environment.cpp [new file with mode: 0644]
lib/StaticAnalyzer/ExplodedGraph.cpp [new file with mode: 0644]
lib/StaticAnalyzer/FlatStore.cpp [new file with mode: 0644]
lib/StaticAnalyzer/GRState.cpp [new file with mode: 0644]
lib/StaticAnalyzer/HTMLDiagnostics.cpp [new file with mode: 0644]
lib/StaticAnalyzer/Makefile [new file with mode: 0644]
lib/StaticAnalyzer/ManagerRegistry.cpp [new file with mode: 0644]
lib/StaticAnalyzer/MemRegion.cpp [new file with mode: 0644]
lib/StaticAnalyzer/PathDiagnostic.cpp [new file with mode: 0644]
lib/StaticAnalyzer/PlistDiagnostics.cpp [new file with mode: 0644]
lib/StaticAnalyzer/README.txt [new file with mode: 0644]
lib/StaticAnalyzer/RangeConstraintManager.cpp [new file with mode: 0644]
lib/StaticAnalyzer/RegionStore.cpp [new file with mode: 0644]
lib/StaticAnalyzer/SValBuilder.cpp [new file with mode: 0644]
lib/StaticAnalyzer/SVals.cpp [new file with mode: 0644]
lib/StaticAnalyzer/SimpleConstraintManager.cpp [new file with mode: 0644]
lib/StaticAnalyzer/SimpleConstraintManager.h [new file with mode: 0644]
lib/StaticAnalyzer/SimpleSValBuilder.cpp [new file with mode: 0644]
lib/StaticAnalyzer/Store.cpp [new file with mode: 0644]
lib/StaticAnalyzer/SymbolManager.cpp [new file with mode: 0644]
lib/StaticAnalyzer/TextPathDiagnostics.cpp [new file with mode: 0644]
tools/driver/CMakeLists.txt
tools/driver/Makefile

index ee451877c6ce639335ffcf053f958ca52bca6398..edfbcb5ce17cd8c97a7172f4bc190b79b9567ea2 100644 (file)
@@ -10,8 +10,8 @@ set( LLVM_USED_LIBS
   clangCodeGen
   clangParse
   clangSema
-  clangEntoCheckers
-  clangEntoCore
+  clangStaticAnalyzerCheckers
+  clangStaticAnalyzerCore
   clangAnalysis
   clangIndex
   clangRewrite
index c8c3c2be2d2e6d3edfca74bd2f65363784365d10..21c5afdc816ae9426e1793eb134cdfae97a6d571 100644 (file)
@@ -6,8 +6,8 @@ set(LLVM_USED_LIBS
     clangDriver
     clangCodeGen
     clangSema
-    clangEntoCheckers
-    clangEntoCore
+    clangStaticAnalyzerCheckers
+    clangStaticAnalyzerCore
     clangIndex
     clangAnalysis
     clangRewrite
index 86bc9ca142bcbe73837f5d98a731d686e426f111..24a2be864d05f2a1f7fd72b8aa42b5606286345c 100644 (file)
@@ -18,7 +18,7 @@ TOOL_NO_EXPORTS = 1
 LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
        selectiondag asmparser
 USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
-           clangSema.a clangEntoCheckers.a clangEntoCore.a clangAnalysis.a clangRewrite.a \
+           clangSema.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangAnalysis.a clangRewrite.a \
            clangAST.a clangParse.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile
index 0100aa2b982ae61305e0ca788e33d206b28070d1..e3aaf1d919d5c1da805fe611b9af1c2fe6997a06 100644 (file)
@@ -7,8 +7,8 @@ set(LLVM_USED_LIBS
   clangSema
   clangAnalysis
   clangSerialization
-  clangEntoCheckers
-  clangEntoCore
+  clangStaticAnalyzerCheckers
+  clangStaticAnalyzerCore
   clangRewrite
   clangAST
   clangParse
index 4fbba9d30f0605dbfb219e2a4b85af16dfc658c9..af0f843149cf6e456352f813f2029440d4345673 100644 (file)
@@ -16,7 +16,7 @@ NO_INSTALL = 1
 TOOL_NO_EXPORTS = 1
 
 LINK_COMPONENTS := asmparser bitreader mc core
-USEDLIBS = clangEntoCheckers.a clangEntoCore.a clangIndex.a clangFrontend.a clangDriver.a \
+USEDLIBS = clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangIndex.a clangFrontend.a clangDriver.a \
           clangSema.a clangAnalysis.a clangSerialization.a \
            clangAST.a clangParse.a clangLex.a clangBasic.a
 
similarity index 99%
rename from include/clang/EntoSA/BugReporter/BugReporter.h
rename to include/clang/StaticAnalyzer/BugReporter/BugReporter.h
index c879d3c94eb10ab74ed859f2f164d9d836978c1f..a5b1980d1ed8a6dc48791a7cdc42e50ddf602b97 100644 (file)
@@ -16,7 +16,7 @@
 #define LLVM_CLANG_GR_BUGREPORTER
 
 #include "clang/Basic/SourceLocation.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/ImmutableSet.h"
similarity index 97%
rename from include/clang/EntoSA/BugReporter/BugType.h
rename to include/clang/StaticAnalyzer/BugReporter/BugType.h
index 1eee141964f5e8d0d55ccbfab8e9605830a03bb2..6e6ec549183a10ec797b25569e1e3a32c5648b18 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
 #define LLVM_CLANG_ANALYSIS_BUGTYPE
 
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "llvm/ADT/FoldingSet.h"
 #include <string>
 
diff --git a/include/clang/StaticAnalyzer/EntoSA/AnalysisConsumer.h b/include/clang/StaticAnalyzer/EntoSA/AnalysisConsumer.h
new file mode 100644 (file)
index 0000000..86f6c72
--- /dev/null
@@ -0,0 +1,39 @@
+//===--- AnalysisConsumer.h - Front-end Analysis Engine Hooks ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header contains the functions necessary for a front-end to run various
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
+#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
+
+#include <string>
+
+namespace clang {
+
+class AnalyzerOptions;
+class ASTConsumer;
+class Preprocessor;
+
+namespace ento {
+
+/// CreateAnalysisConsumer - Creates an ASTConsumer to run various code
+/// analysis passes.  (The set of analyses run is controlled by command-line
+/// options.)
+ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
+                                    const std::string &output,
+                                    const AnalyzerOptions& Opts);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/EntoSA/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/EntoSA/BugReporter/BugReporter.h
new file mode 100644 (file)
index 0000000..a5b1980
--- /dev/null
@@ -0,0 +1,486 @@
+//===---  BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating
+//  PathDiagnostics for analyses based on GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_BUGREPORTER
+#define LLVM_CLANG_GR_BUGREPORTER
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/ADT/SmallSet.h"
+#include <list>
+
+namespace clang {
+
+class ASTContext;
+class Diagnostic;
+class Stmt;
+class ParentMap;
+
+namespace ento {
+
+class PathDiagnostic;
+class PathDiagnosticPiece;
+class PathDiagnosticClient;
+class ExplodedNode;
+class ExplodedGraph;
+class BugReporter;
+class BugReporterContext;
+class ExprEngine;
+class GRState;
+class BugType;
+
+//===----------------------------------------------------------------------===//
+// Interface for individual bug reports.
+//===----------------------------------------------------------------------===//
+
+class BugReporterVisitor : public llvm::FoldingSetNode {
+public:
+  virtual ~BugReporterVisitor();
+  virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
+                                         const ExplodedNode* PrevN,
+                                         BugReporterContext& BRC) = 0;
+
+  virtual bool isOwnedByReporterContext() { return true; }
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+};
+
+// FIXME: Combine this with RangedBugReport and remove RangedBugReport.
+class BugReport : public BugReporterVisitor {
+protected:
+  BugType& BT;
+  std::string ShortDescription;
+  std::string Description;
+  const ExplodedNode *ErrorNode;
+  mutable SourceRange R;
+
+protected:
+  friend class BugReporter;
+  friend class BugReportEquivClass;
+
+  virtual void Profile(llvm::FoldingSetNodeID& hash) const {
+    hash.AddInteger(getLocation().getRawEncoding());
+    hash.AddString(Description);
+  }
+
+public:
+  class NodeResolver {
+  public:
+    virtual ~NodeResolver() {}
+    virtual const ExplodedNode*
+            getOriginalNode(const ExplodedNode* N) = 0;
+  };
+
+  BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
+    : BT(bt), Description(desc), ErrorNode(errornode) {}
+
+  BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
+            const ExplodedNode *errornode)
+  : BT(bt), ShortDescription(shortDesc), Description(desc),
+    ErrorNode(errornode) {}
+
+  virtual ~BugReport();
+
+  virtual bool isOwnedByReporterContext() { return false; }
+
+  const BugType& getBugType() const { return BT; }
+  BugType& getBugType() { return BT; }
+
+  // FIXME: Perhaps this should be moved into a subclass?
+  const ExplodedNode* getErrorNode() const { return ErrorNode; }
+
+  // FIXME: Do we need this?  Maybe getLocation() should return a ProgramPoint
+  // object.
+  // FIXME: If we do need it, we can probably just make it private to
+  // BugReporter.
+  const Stmt* getStmt() const;
+
+  const llvm::StringRef getDescription() const { return Description; }
+
+  const llvm::StringRef getShortDescription() const {
+    return ShortDescription.empty() ? Description : ShortDescription;
+  }
+
+  // FIXME: Is this needed?
+  virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
+    return std::make_pair((const char**)0,(const char**)0);
+  }
+
+  // FIXME: Perhaps move this into a subclass.
+  virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
+                                          const ExplodedNode* N);
+
+  /// getLocation - Return the "definitive" location of the reported bug.
+  ///  While a bug can span an entire path, usually there is a specific
+  ///  location that can be used to identify where the key issue occured.
+  ///  This location is used by clients rendering diagnostics.
+  virtual SourceLocation getLocation() const;
+
+  typedef const SourceRange *ranges_iterator;
+
+  /// getRanges - Returns the source ranges associated with this bug.
+  virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
+
+  virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
+                                         const ExplodedNode* PrevN,
+                                         BugReporterContext& BR);
+
+  virtual void registerInitialVisitors(BugReporterContext& BRC,
+                                       const ExplodedNode* N) {}
+};
+
+//===----------------------------------------------------------------------===//
+// BugTypes (collections of related reports).
+//===----------------------------------------------------------------------===//
+
+class BugReportEquivClass : public llvm::FoldingSetNode {
+  // List of *owned* BugReport objects.
+  std::list<BugReport*> Reports;
+
+  friend class BugReporter;
+  void AddReport(BugReport* R) { Reports.push_back(R); }
+public:
+  BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
+  ~BugReportEquivClass();
+
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    assert(!Reports.empty());
+    (*Reports.begin())->Profile(ID);
+  }
+
+  class iterator {
+    std::list<BugReport*>::iterator impl;
+  public:
+    iterator(std::list<BugReport*>::iterator i) : impl(i) {}
+    iterator& operator++() { ++impl; return *this; }
+    bool operator==(const iterator& I) const { return I.impl == impl; }
+    bool operator!=(const iterator& I) const { return I.impl != impl; }
+    BugReport* operator*() const { return *impl; }
+    BugReport* operator->() const { return *impl; }
+  };
+
+  class const_iterator {
+    std::list<BugReport*>::const_iterator impl;
+  public:
+    const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
+    const_iterator& operator++() { ++impl; return *this; }
+    bool operator==(const const_iterator& I) const { return I.impl == impl; }
+    bool operator!=(const const_iterator& I) const { return I.impl != impl; }
+    const BugReport* operator*() const { return *impl; }
+    const BugReport* operator->() const { return *impl; }
+  };
+
+  iterator begin() { return iterator(Reports.begin()); }
+  iterator end() { return iterator(Reports.end()); }
+
+  const_iterator begin() const { return const_iterator(Reports.begin()); }
+  const_iterator end() const { return const_iterator(Reports.end()); }
+};
+
+
+//===----------------------------------------------------------------------===//
+// Specialized subclasses of BugReport.
+//===----------------------------------------------------------------------===//
+
+// FIXME: Collapse this with the default BugReport class.
+class RangedBugReport : public BugReport {
+  llvm::SmallVector<SourceRange, 4> Ranges;
+public:
+  RangedBugReport(BugType& D, llvm::StringRef description,
+                  ExplodedNode *errornode)
+    : BugReport(D, description, errornode) {}
+
+  RangedBugReport(BugType& D, llvm::StringRef shortDescription,
+                  llvm::StringRef description, ExplodedNode *errornode)
+  : BugReport(D, shortDescription, description, errornode) {}
+
+  ~RangedBugReport();
+
+  // FIXME: Move this out of line.
+  void addRange(SourceRange R) {
+    assert(R.isValid());
+    Ranges.push_back(R);
+  }
+
+  virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
+    return std::make_pair(Ranges.begin(), Ranges.end());
+  }
+};
+
+class EnhancedBugReport : public RangedBugReport {
+public:
+  typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
+                                 const ExplodedNode *N);
+
+private:
+  typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
+  Creators creators;
+
+public:
+  EnhancedBugReport(BugType& D, llvm::StringRef description,
+                    ExplodedNode *errornode)
+   : RangedBugReport(D, description, errornode) {}
+
+  EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
+                   llvm::StringRef description, ExplodedNode *errornode)
+    : RangedBugReport(D, shortDescription, description, errornode) {}
+
+  ~EnhancedBugReport() {}
+
+  void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
+    for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
+      I->first(BRC, I->second, N);
+  }
+
+  void addVisitorCreator(VisitorCreator creator, const void *data) {
+    creators.push_back(std::make_pair(creator, data));
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// BugReporter and friends.
+//===----------------------------------------------------------------------===//
+
+class BugReporterData {
+public:
+  virtual ~BugReporterData();
+  virtual Diagnostic& getDiagnostic() = 0;
+  virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
+  virtual ASTContext& getASTContext() = 0;
+  virtual SourceManager& getSourceManager() = 0;
+};
+
+class BugReporter {
+public:
+  enum Kind { BaseBRKind, GRBugReporterKind };
+
+private:
+  typedef llvm::ImmutableSet<BugType*> BugTypesTy;
+  BugTypesTy::Factory F;
+  BugTypesTy BugTypes;
+
+  const Kind kind;
+  BugReporterData& D;
+
+  void FlushReport(BugReportEquivClass& EQ);
+
+protected:
+  BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
+                                            D(d) {}
+
+public:
+  BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
+                                    D(d) {}
+  virtual ~BugReporter();
+
+  void FlushReports();
+
+  Kind getKind() const { return kind; }
+
+  Diagnostic& getDiagnostic() {
+    return D.getDiagnostic();
+  }
+
+  PathDiagnosticClient* getPathDiagnosticClient() {
+    return D.getPathDiagnosticClient();
+  }
+
+  typedef BugTypesTy::iterator iterator;
+  iterator begin() { return BugTypes.begin(); }
+  iterator end() { return BugTypes.end(); }
+
+  ASTContext& getContext() { return D.getASTContext(); }
+
+  SourceManager& getSourceManager() { return D.getSourceManager(); }
+
+  virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
+        llvm::SmallVectorImpl<BugReport *> &bugReports) {}
+
+  void Register(BugType *BT);
+
+  void EmitReport(BugReport *R);
+
+  void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
+                       SourceLocation Loc,
+                       SourceRange* RangeBeg, unsigned NumRanges);
+
+  void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
+                       llvm::StringRef BugStr, SourceLocation Loc,
+                       SourceRange* RangeBeg, unsigned NumRanges);
+
+
+  void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
+                       SourceLocation Loc) {
+    EmitBasicReport(BugName, BugStr, Loc, 0, 0);
+  }
+
+  void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
+                       llvm::StringRef BugStr, SourceLocation Loc) {
+    EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
+  }
+
+  void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
+                       SourceLocation Loc, SourceRange R) {
+    EmitBasicReport(BugName, BugStr, Loc, &R, 1);
+  }
+
+  void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
+                       llvm::StringRef BugStr, SourceLocation Loc,
+                       SourceRange R) {
+    EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
+  }
+
+  static bool classof(const BugReporter* R) { return true; }
+};
+
+// FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
+class GRBugReporter : public BugReporter {
+  ExprEngine& Eng;
+  llvm::SmallSet<SymbolRef, 10> NotableSymbols;
+public:
+  GRBugReporter(BugReporterData& d, ExprEngine& eng)
+    : BugReporter(d, GRBugReporterKind), Eng(eng) {}
+
+  virtual ~GRBugReporter();
+
+  /// getEngine - Return the analysis engine used to analyze a given
+  ///  function or method.
+  ExprEngine &getEngine() { return Eng; }
+
+  /// getGraph - Get the exploded graph created by the analysis engine
+  ///  for the analyzed method or function.
+  ExplodedGraph &getGraph();
+
+  /// getStateManager - Return the state manager used by the analysis
+  ///  engine.
+  GRStateManager &getStateManager();
+
+  virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
+                     llvm::SmallVectorImpl<BugReport*> &bugReports);
+
+  void addNotableSymbol(SymbolRef Sym) {
+    NotableSymbols.insert(Sym);
+  }
+
+  bool isNotable(SymbolRef Sym) const {
+    return (bool) NotableSymbols.count(Sym);
+  }
+
+  /// classof - Used by isa<>, cast<>, and dyn_cast<>.
+  static bool classof(const BugReporter* R) {
+    return R->getKind() == GRBugReporterKind;
+  }
+};
+
+class BugReporterContext {
+  GRBugReporter &BR;
+  // Not the most efficient data structure, but we use an ImmutableList for the
+  // Callbacks because it is safe to make additions to list during iteration.
+  llvm::ImmutableList<BugReporterVisitor*>::Factory F;
+  llvm::ImmutableList<BugReporterVisitor*> Callbacks;
+  llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
+public:
+  BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
+  virtual ~BugReporterContext();
+
+  void addVisitor(BugReporterVisitor* visitor);
+
+  typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
+  visitor_iterator visitor_begin() { return Callbacks.begin(); }
+  visitor_iterator visitor_end() { return Callbacks.end(); }
+
+  GRBugReporter& getBugReporter() { return BR; }
+
+  ExplodedGraph &getGraph() { return BR.getGraph(); }
+
+  void addNotableSymbol(SymbolRef Sym) {
+    // FIXME: For now forward to GRBugReporter.
+    BR.addNotableSymbol(Sym);
+  }
+
+  bool isNotable(SymbolRef Sym) const {
+    // FIXME: For now forward to GRBugReporter.
+    return BR.isNotable(Sym);
+  }
+
+  GRStateManager& getStateManager() {
+    return BR.getStateManager();
+  }
+
+  SValBuilder& getSValBuilder() {
+    return getStateManager().getSValBuilder();
+  }
+
+  ASTContext& getASTContext() {
+    return BR.getContext();
+  }
+
+  SourceManager& getSourceManager() {
+    return BR.getSourceManager();
+  }
+
+  virtual BugReport::NodeResolver& getNodeResolver() = 0;
+};
+
+class DiagBugReport : public RangedBugReport {
+  std::list<std::string> Strs;
+  FullSourceLoc L;
+public:
+  DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
+  RangedBugReport(D, desc, 0), L(l) {}
+
+  virtual ~DiagBugReport() {}
+
+  // FIXME: Move out-of-line (virtual function).
+  SourceLocation getLocation() const { return L; }
+
+  void addString(llvm::StringRef s) { Strs.push_back(s); }
+
+  typedef std::list<std::string>::const_iterator str_iterator;
+  str_iterator str_begin() const { return Strs.begin(); }
+  str_iterator str_end() const { return Strs.end(); }
+};
+
+//===----------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
+
+namespace bugreporter {
+
+const Stmt *GetDerefExpr(const ExplodedNode *N);
+const Stmt *GetDenomExpr(const ExplodedNode *N);
+const Stmt *GetCalleeExpr(const ExplodedNode *N);
+const Stmt *GetRetValExpr(const ExplodedNode *N);
+
+void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
+                                   const ExplodedNode* N);
+
+void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
+                           const ExplodedNode *N);
+
+void registerNilReceiverVisitor(BugReporterContext &BRC);
+
+void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
+                               const ExplodedNode *N);
+
+} // end namespace clang::bugreporter
+
+//===----------------------------------------------------------------------===//
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/EntoSA/BugReporter/BugType.h b/include/clang/StaticAnalyzer/EntoSA/BugReporter/BugType.h
new file mode 100644 (file)
index 0000000..6e6ec54
--- /dev/null
@@ -0,0 +1,76 @@
+//===---  BugType.h - Bug Information Desciption ----------------*- 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 BugType, a class representing a bug type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
+#define LLVM_CLANG_ANALYSIS_BUGTYPE
+
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "llvm/ADT/FoldingSet.h"
+#include <string>
+
+namespace clang {
+
+namespace ento {
+
+class ExplodedNode;
+class ExprEngine;
+
+class BugType {
+private:
+  const std::string Name;
+  const std::string Category;
+  llvm::FoldingSet<BugReportEquivClass> EQClasses;
+  friend class BugReporter;
+  bool SuppressonSink;
+public:
+  BugType(llvm::StringRef name, llvm::StringRef cat)
+    : Name(name), Category(cat), SuppressonSink(false) {}
+  virtual ~BugType();
+
+  // FIXME: Should these be made strings as well?
+  llvm::StringRef getName() const { return Name; }
+  llvm::StringRef getCategory() const { return Category; }
+  
+  /// isSuppressOnSink - Returns true if bug reports associated with this bug
+  ///  type should be suppressed if the end node of the report is post-dominated
+  ///  by a sink node.
+  bool isSuppressOnSink() const { return SuppressonSink; }
+  void setSuppressOnSink(bool x) { SuppressonSink = x; }
+
+  virtual void FlushReports(BugReporter& BR);
+
+  typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
+  iterator begin() { return EQClasses.begin(); }
+  iterator end() { return EQClasses.end(); }
+
+  typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
+  const_iterator begin() const { return EQClasses.begin(); }
+  const_iterator end() const { return EQClasses.end(); }
+};
+
+class BuiltinBug : public BugType {
+  const std::string desc;
+public:
+  BuiltinBug(const char *name, const char *description)
+    : BugType(name, "Logic error"), desc(description) {}
+  
+  BuiltinBug(const char *name)
+    : BugType(name, "Logic error"), desc(name) {}
+  
+  llvm::StringRef getDescription() const { return desc; }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+#endif
diff --git a/include/clang/StaticAnalyzer/EntoSA/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/EntoSA/BugReporter/PathDiagnostic.h
new file mode 100644 (file)
index 0000000..6d53c09
--- /dev/null
@@ -0,0 +1,500 @@
+//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- 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 PathDiagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
+#define LLVM_CLANG_PATH_DIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/FoldingSet.h"
+#include <deque>
+#include <iterator>
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class Decl;
+class SourceManager;
+class Stmt;
+
+namespace ento {
+
+//===----------------------------------------------------------------------===//
+// High-level interface for handlers of path-sensitive diagnostics.
+//===----------------------------------------------------------------------===//
+
+class PathDiagnostic;
+
+class PathDiagnosticClient : public DiagnosticClient  {
+public:
+  PathDiagnosticClient() {}
+
+  virtual ~PathDiagnosticClient() {}
+  
+  virtual void
+  FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade = 0) = 0;
+  
+  void FlushDiagnostics(llvm::SmallVectorImpl<std::string> &FilesMade) {
+    FlushDiagnostics(&FilesMade);
+  }
+  
+  virtual llvm::StringRef getName() const = 0;
+  
+  virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+                                const DiagnosticInfo &Info);
+  virtual void HandlePathDiagnostic(const PathDiagnostic* D) = 0;
+
+  enum PathGenerationScheme { Minimal, Extensive };
+  virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
+  virtual bool supportsLogicalOpControlFlow() const { return false; }
+  virtual bool supportsAllBlockEdges() const { return false; }
+  virtual bool useVerboseDescription() const { return true; }
+};
+
+//===----------------------------------------------------------------------===//
+// Path-sensitive diagnostics.
+//===----------------------------------------------------------------------===//
+
+class PathDiagnosticRange : public SourceRange {
+public:
+  const bool isPoint;
+
+  PathDiagnosticRange(const SourceRange &R, bool isP = false)
+    : SourceRange(R), isPoint(isP) {}
+};
+
+class PathDiagnosticLocation {
+private:
+  enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
+  SourceRange R;
+  const Stmt *S;
+  const Decl *D;
+  const SourceManager *SM;
+public:
+  PathDiagnosticLocation()
+    : K(SingleLocK), S(0), D(0), SM(0) {}
+
+  PathDiagnosticLocation(FullSourceLoc L)
+    : K(SingleLocK), R(L, L), S(0), D(0), SM(&L.getManager()) {}
+
+  PathDiagnosticLocation(const Stmt *s, const SourceManager &sm)
+    : K(StmtK), S(s), D(0), SM(&sm) {}
+
+  PathDiagnosticLocation(SourceRange r, const SourceManager &sm)
+    : K(RangeK), R(r), S(0), D(0), SM(&sm) {}
+
+  PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
+    : K(DeclK), S(0), D(d), SM(&sm) {}
+
+  bool operator==(const PathDiagnosticLocation &X) const {
+    return K == X.K && R == X.R && S == X.S && D == X.D;
+  }
+
+  bool operator!=(const PathDiagnosticLocation &X) const {
+    return K != X.K || R != X.R || S != X.S || D != X.D;;
+  }
+
+  PathDiagnosticLocation& operator=(const PathDiagnosticLocation &X) {
+    K = X.K;
+    R = X.R;
+    S = X.S;
+    D = X.D;
+    SM = X.SM;
+    return *this;
+  }
+
+  bool isValid() const {
+    return SM != 0;
+  }
+
+  const SourceManager& getSourceManager() const { assert(isValid());return *SM;}
+
+  FullSourceLoc asLocation() const;
+  PathDiagnosticRange asRange() const;
+  const Stmt *asStmt() const { assert(isValid()); return S; }
+  const Decl *asDecl() const { assert(isValid()); return D; }
+
+  bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
+
+  void invalidate() {
+    *this = PathDiagnosticLocation();
+  }
+
+  void flatten();
+
+  const SourceManager& getManager() const { assert(isValid()); return *SM; }
+  
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
+class PathDiagnosticLocationPair {
+private:
+  PathDiagnosticLocation Start, End;
+public:
+  PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
+                             const PathDiagnosticLocation &end)
+    : Start(start), End(end) {}
+
+  const PathDiagnosticLocation &getStart() const { return Start; }
+  const PathDiagnosticLocation &getEnd() const { return End; }
+
+  void flatten() {
+    Start.flatten();
+    End.flatten();
+  }
+  
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Start.Profile(ID);
+    End.Profile(ID);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// Path "pieces" for path-sensitive diagnostics.
+//===----------------------------------------------------------------------===//
+
+class PathDiagnosticPiece {
+public:
+  enum Kind { ControlFlow, Event, Macro };
+  enum DisplayHint { Above, Below };
+
+private:
+  const std::string str;
+  std::vector<FixItHint> FixItHints;
+  const Kind kind;
+  const DisplayHint Hint;
+  std::vector<SourceRange> ranges;
+
+  // Do not implement:
+  PathDiagnosticPiece();
+  PathDiagnosticPiece(const PathDiagnosticPiece &P);
+  PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
+
+protected:
+  PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint = Below);
+
+  PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
+
+public:
+  virtual ~PathDiagnosticPiece();
+
+  const std::string& getString() const { return str; }
+
+  /// getDisplayHint - Return a hint indicating where the diagnostic should
+  ///  be displayed by the PathDiagnosticClient.
+  DisplayHint getDisplayHint() const { return Hint; }
+
+  virtual PathDiagnosticLocation getLocation() const = 0;
+  virtual void flattenLocations() = 0;
+
+  Kind getKind() const { return kind; }
+
+  void addRange(SourceRange R) { ranges.push_back(R); }
+
+  void addRange(SourceLocation B, SourceLocation E) {
+    ranges.push_back(SourceRange(B,E));
+  }
+
+  void addFixItHint(const FixItHint& Hint) {
+    FixItHints.push_back(Hint);
+  }
+
+  typedef const SourceRange* range_iterator;
+
+  range_iterator ranges_begin() const {
+    return ranges.empty() ? NULL : &ranges[0];
+  }
+
+  range_iterator ranges_end() const {
+    return ranges_begin() + ranges.size();
+  }
+
+  typedef const FixItHint *fixit_iterator;
+
+  fixit_iterator fixit_begin() const {
+    return FixItHints.empty()? 0 : &FixItHints[0];
+  }
+
+  fixit_iterator fixit_end() const {
+    return FixItHints.empty()? 0
+                   : &FixItHints[0] + FixItHints.size();
+  }
+
+  static inline bool classof(const PathDiagnosticPiece* P) {
+    return true;
+  }
+  
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
+class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
+private:
+  PathDiagnosticLocation Pos;
+public:
+  PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
+                          llvm::StringRef s,
+                          PathDiagnosticPiece::Kind k,
+                          bool addPosRange = true)
+  : PathDiagnosticPiece(s, k), Pos(pos) {
+    assert(Pos.asLocation().isValid() &&
+           "PathDiagnosticSpotPiece's must have a valid location.");
+    if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
+  }
+
+  PathDiagnosticLocation getLocation() const { return Pos; }
+  virtual void flattenLocations() { Pos.flatten(); }
+  
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
+class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
+
+public:
+  PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
+                           llvm::StringRef s, bool addPosRange = true)
+    : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
+
+  ~PathDiagnosticEventPiece();
+
+  static inline bool classof(const PathDiagnosticPiece* P) {
+    return P->getKind() == Event;
+  }
+};
+
+class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
+  std::vector<PathDiagnosticLocationPair> LPairs;
+public:
+  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
+                                 const PathDiagnosticLocation &endPos,
+                                 llvm::StringRef s)
+    : PathDiagnosticPiece(s, ControlFlow) {
+      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+    }
+
+  PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
+                                 const PathDiagnosticLocation &endPos)
+    : PathDiagnosticPiece(ControlFlow) {
+      LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+    }
+
+  ~PathDiagnosticControlFlowPiece();
+
+  PathDiagnosticLocation getStartLocation() const {
+    assert(!LPairs.empty() &&
+           "PathDiagnosticControlFlowPiece needs at least one location.");
+    return LPairs[0].getStart();
+  }
+
+  PathDiagnosticLocation getEndLocation() const {
+    assert(!LPairs.empty() &&
+           "PathDiagnosticControlFlowPiece needs at least one location.");
+    return LPairs[0].getEnd();
+  }
+
+  void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
+
+  virtual PathDiagnosticLocation getLocation() const {
+    return getStartLocation();
+  }
+
+  typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
+  iterator begin() { return LPairs.begin(); }
+  iterator end()   { return LPairs.end(); }
+
+  virtual void flattenLocations() {
+    for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
+  }
+
+  typedef std::vector<PathDiagnosticLocationPair>::const_iterator
+          const_iterator;
+  const_iterator begin() const { return LPairs.begin(); }
+  const_iterator end() const   { return LPairs.end(); }
+
+  static inline bool classof(const PathDiagnosticPiece* P) {
+    return P->getKind() == ControlFlow;
+  }
+  
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
+class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
+  std::vector<PathDiagnosticPiece*> SubPieces;
+public:
+  PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
+    : PathDiagnosticSpotPiece(pos, "", Macro) {}
+
+  ~PathDiagnosticMacroPiece();
+
+  bool containsEvent() const;
+
+  void push_back(PathDiagnosticPiece* P) { SubPieces.push_back(P); }
+
+  typedef std::vector<PathDiagnosticPiece*>::iterator iterator;
+  iterator begin() { return SubPieces.begin(); }
+  iterator end() { return SubPieces.end(); }
+
+  virtual void flattenLocations() {
+    PathDiagnosticSpotPiece::flattenLocations();
+    for (iterator I=begin(), E=end(); I!=E; ++I) (*I)->flattenLocations();
+  }
+
+  typedef std::vector<PathDiagnosticPiece*>::const_iterator const_iterator;
+  const_iterator begin() const { return SubPieces.begin(); }
+  const_iterator end() const { return SubPieces.end(); }
+
+  static inline bool classof(const PathDiagnosticPiece* P) {
+    return P->getKind() == Macro;
+  }
+  
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const;
+};
+
+/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
+///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
+///  each which represent the pieces of the path.
+class PathDiagnostic : public llvm::FoldingSetNode {
+  std::deque<PathDiagnosticPiece*> path;
+  unsigned Size;
+  std::string BugType;
+  std::string Desc;
+  std::string Category;
+  std::deque<std::string> OtherDesc;
+
+public:
+  PathDiagnostic();
+
+  PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
+                 llvm::StringRef category);
+
+  ~PathDiagnostic();
+
+  llvm::StringRef getDescription() const { return Desc; }
+  llvm::StringRef getBugType() const { return BugType; }
+  llvm::StringRef getCategory() const { return Category; }
+
+  typedef std::deque<std::string>::const_iterator meta_iterator;
+  meta_iterator meta_begin() const { return OtherDesc.begin(); }
+  meta_iterator meta_end() const { return OtherDesc.end(); }
+  void addMeta(llvm::StringRef s) { OtherDesc.push_back(s); }
+
+  PathDiagnosticLocation getLocation() const {
+    assert(Size > 0 && "getLocation() requires a non-empty PathDiagnostic.");
+    return rbegin()->getLocation();
+  }
+
+  void push_front(PathDiagnosticPiece* piece) {
+    assert(piece);
+    path.push_front(piece);
+    ++Size;
+  }
+
+  void push_back(PathDiagnosticPiece* piece) {
+    assert(piece);
+    path.push_back(piece);
+    ++Size;
+  }
+
+  PathDiagnosticPiece* back() {
+    return path.back();
+  }
+
+  const PathDiagnosticPiece* back() const {
+    return path.back();
+  }
+
+  unsigned size() const { return Size; }
+  bool empty() const { return Size == 0; }
+
+  void resetPath(bool deletePieces = true);
+
+  class iterator {
+  public:
+    typedef std::deque<PathDiagnosticPiece*>::iterator ImplTy;
+
+    typedef PathDiagnosticPiece              value_type;
+    typedef value_type&                      reference;
+    typedef value_type*                      pointer;
+    typedef ptrdiff_t                        difference_type;
+    typedef std::bidirectional_iterator_tag  iterator_category;
+
+  private:
+    ImplTy I;
+
+  public:
+    iterator(const ImplTy& i) : I(i) {}
+
+    bool operator==(const iterator& X) const { return I == X.I; }
+    bool operator!=(const iterator& X) const { return I != X.I; }
+
+    PathDiagnosticPiece& operator*() const { return **I; }
+    PathDiagnosticPiece* operator->() const { return *I; }
+
+    iterator& operator++() { ++I; return *this; }
+    iterator& operator--() { --I; return *this; }
+  };
+
+  class const_iterator {
+  public:
+    typedef std::deque<PathDiagnosticPiece*>::const_iterator ImplTy;
+
+    typedef const PathDiagnosticPiece        value_type;
+    typedef value_type&                      reference;
+    typedef value_type*                      pointer;
+    typedef ptrdiff_t                        difference_type;
+    typedef std::bidirectional_iterator_tag  iterator_category;
+
+  private:
+    ImplTy I;
+
+  public:
+    const_iterator(const ImplTy& i) : I(i) {}
+
+    bool operator==(const const_iterator& X) const { return I == X.I; }
+    bool operator!=(const const_iterator& X) const { return I != X.I; }
+
+    reference operator*() const { return **I; }
+    pointer operator->() const { return *I; }
+
+    const_iterator& operator++() { ++I; return *this; }
+    const_iterator& operator--() { --I; return *this; }
+  };
+
+  typedef std::reverse_iterator<iterator>       reverse_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  // forward iterator creation methods.
+
+  iterator begin() { return path.begin(); }
+  iterator end() { return path.end(); }
+
+  const_iterator begin() const { return path.begin(); }
+  const_iterator end() const { return path.end(); }
+
+  // reverse iterator creation methods.
+  reverse_iterator rbegin()            { return reverse_iterator(end()); }
+  const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
+  reverse_iterator rend()              { return reverse_iterator(begin()); }
+  const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
+
+  void flattenLocations() {
+    for (iterator I = begin(), E = end(); I != E; ++I) I->flattenLocations();
+  }
+  
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+};  
+
+} // end GR namespace
+
+} //end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.h b/include/clang/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.h
new file mode 100644 (file)
index 0000000..f9cce9c
--- /dev/null
@@ -0,0 +1,35 @@
+//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NullDerefChecker and UndefDerefChecker, two builtin checks
+// in ExprEngine that check for null and undefined pointers at loads
+// and stores.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_DEREFCHECKER
+#define LLVM_CLANG_GR_DEREFCHECKER
+
+#include <utility>
+
+namespace clang {
+
+namespace ento {
+
+class ExprEngine;
+class ExplodedNode;
+
+std::pair<ExplodedNode * const *, ExplodedNode * const *>
+GetImplicitNullDereferences(ExprEngine &Eng);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/EntoSA/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/EntoSA/Checkers/LocalCheckers.h
new file mode 100644 (file)
index 0000000..e0f002b
--- /dev/null
@@ -0,0 +1,67 @@
+//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- 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 interface to call a set of intra-procedural (local)
+//  checkers that use flow/path-sensitive analyses to find bugs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_LOCALCHECKERS_H
+#define LLVM_CLANG_GR_LOCALCHECKERS_H
+
+namespace clang {
+
+class CFG;
+class Decl;
+class Diagnostic;
+class ASTContext;
+class LangOptions;
+class ParentMap;
+class LiveVariables;
+class ObjCImplementationDecl;
+class LangOptions;
+class TranslationUnitDecl;
+
+namespace ento {
+
+class PathDiagnosticClient;
+class TransferFuncs;
+class BugType;
+class BugReporter;
+class ExprEngine;
+
+void CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &map, 
+                     BugReporter& BR);
+
+TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+                                  const LangOptions& lopts);
+
+void CheckObjCDealloc(const ObjCImplementationDecl* D, const LangOptions& L,
+                      BugReporter& BR);
+
+void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
+                                BugReporter& BR);
+
+void CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter& BR);
+
+void RegisterAppleChecks(ExprEngine& Eng, const Decl &D);
+void RegisterExperimentalChecks(ExprEngine &Eng);
+void RegisterExperimentalInternalChecks(ExprEngine &Eng);
+
+void CheckLLVMConventions(TranslationUnitDecl &TU, BugReporter &BR);
+void CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR);
+void CheckSizeofPointer(const Decl *D, BugReporter &BR);
+
+void RegisterCallInliner(ExprEngine &Eng);
+
+} // end GR namespace
+
+} // end namespace clang
+
+#endif
similarity index 96%
rename from include/clang/EntoSA/ManagerRegistry.h
rename to include/clang/StaticAnalyzer/EntoSA/ManagerRegistry.h
index 43657a5471419af9d3ea750bbfff07c971071684..1b8498042830e057e8d9cee39304046b7fae76b4 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef LLVM_CLANG_GR_MANAGER_REGISTRY_H
 #define LLVM_CLANG_GR_MANAGER_REGISTRY_H
 
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 
 namespace clang {
 
similarity index 98%
rename from include/clang/EntoSA/PathSensitive/AnalysisManager.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/AnalysisManager.h
index 95d954ec86320573b76e99bef9985368042b74ae..ba86ed8ba2e39f26ebe0aef15c7495a63ef256dc 100644 (file)
@@ -16,8 +16,8 @@
 #define LLVM_CLANG_GR_ANALYSISMANAGER_H
 
 #include "clang/Analysis/AnalysisContext.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
 
 namespace clang {
 
similarity index 99%
rename from include/clang/EntoSA/PathSensitive/BasicValueFactory.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/BasicValueFactory.h
index 061508ecbdd6d13d5d7798007fe089a10939a23d..4cac8b64175b1a9643374ad88339ae71031fdda0 100644 (file)
@@ -16,7 +16,7 @@
 #ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
 #define LLVM_CLANG_GR_BASICVALUEFACTORY_H
 
-#include "clang/EntoSA/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
 #include "clang/AST/ASTContext.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/APSInt.h"
similarity index 99%
rename from include/clang/EntoSA/PathSensitive/Checker.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/Checker.h
index a536955c958ad3bed4db4cfcfefd677be55ad497..b2103a2426b223ef86fa0657c1ba8ea4a77e0d49 100644 (file)
@@ -16,7 +16,7 @@
 #define LLVM_CLANG_GR_CHECKER
 
 #include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 //===----------------------------------------------------------------------===//
 // Checker interface.
similarity index 92%
rename from include/clang/EntoSA/PathSensitive/CheckerVisitor.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/CheckerVisitor.h
index 62ce943cdbc35631d6a784cb27df0cd2ef6d9e68..68677f5503b1085f335b0d43cca96ea4447248fa 100644 (file)
@@ -13,7 +13,7 @@
 
 #ifndef LLVM_CLANG_GR_CHECKERVISITOR
 #define LLVM_CLANG_GR_CHECKERVISITOR
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 
 namespace clang {
 
@@ -51,7 +51,7 @@ public:
 case Stmt::NAME ## Class:\
 static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
 break;
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
     }
   }
   
@@ -70,7 +70,7 @@ case Stmt::NAME ## Class:\
 static_cast<ImplClass*>(this)->\
 PostVisit ## NAME(C,static_cast<const NAME*>(S));\
 break;
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
     }
   }
 
@@ -101,7 +101,7 @@ void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\
 void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
   static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
 }
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.def"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
 };
 
 } // end GR namespace
similarity index 97%
rename from include/clang/EntoSA/PathSensitive/ConstraintManager.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/ConstraintManager.h
index b9e723ca4a6e16c8d96a054c0e6bf6d46883f088..81f4558e6a603dc4374479d32af58c4aebe1648a 100644 (file)
@@ -15,7 +15,7 @@
 #define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
 
 // FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
-#include "clang/EntoSA/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
 
 namespace llvm {
 class APSInt;
similarity index 98%
rename from include/clang/EntoSA/PathSensitive/CoreEngine.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/CoreEngine.h
index 45e7fdc64504c27c8bccd3fe8b48c28114e80cac..3d63982d73bfe3087bf46d0f35f82fd32d1db835 100644 (file)
 #define LLVM_CLANG_GR_COREENGINE
 
 #include "clang/AST/Expr.h"
-#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
-#include "clang/EntoSA/PathSensitive/WorkList.h"
-#include "clang/EntoSA/PathSensitive/BlockCounter.h"
-#include "clang/EntoSA/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/WorkList.h"
+#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
+#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
 #include "llvm/ADT/OwningPtr.h"
 
 namespace clang {
similarity index 96%
rename from include/clang/EntoSA/PathSensitive/Environment.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/Environment.h
index 1e88e1605ee8e94a10d3c42f4adab5998d632447..8f2ebce6700ef863ad3e3d8be7562e79f127baa5 100644 (file)
@@ -14,8 +14,8 @@
 #ifndef LLVM_CLANG_GR_ENVIRONMENT_H
 #define LLVM_CLANG_GR_ENVIRONMENT_H
 
-#include "clang/EntoSA/PathSensitive/Store.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
 #include "llvm/ADT/ImmutableMap.h"
 
 namespace clang {
similarity index 98%
rename from include/clang/EntoSA/PathSensitive/ExprEngine.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/ExprEngine.h
index d10e76b20271ee937fd3ea902f66d2b3be7b0861..407691a20bb3968e2085eb2c236d0e52a7ca8bcd 100644 (file)
 #ifndef LLVM_CLANG_GR_EXPRENGINE
 #define LLVM_CLANG_GR_EXPRENGINE
 
-#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
-#include "clang/EntoSA/PathSensitive/SubEngine.h"
-#include "clang/EntoSA/PathSensitive/CoreEngine.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/ExprCXX.h"
similarity index 97%
rename from include/clang/EntoSA/PathSensitive/ExprEngineBuilders.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/ExprEngineBuilders.h
index 91df6121a7859f25129b746e372fab7768aaeb10..965ec3e1c31c2f8ddee2214b46926c93d84562b2 100644 (file)
@@ -14,7 +14,7 @@
 
 #ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
 #define LLVM_CLANG_GR_EXPRENGINE_BUILDERS
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/Analysis/Support/SaveAndRestore.h"
 
 namespace clang {
similarity index 99%
rename from include/clang/EntoSA/PathSensitive/GRState.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/GRState.h
index 8e2ab072997b9d323c12eaf69b69bb20cedcc991..dcdb6e26cbbd571887c58200dc66da93528e7858 100644 (file)
 #ifndef LLVM_CLANG_GR_VALUESTATE_H
 #define LLVM_CLANG_GR_VALUESTATE_H
 
-#include "clang/EntoSA/PathSensitive/ConstraintManager.h"
-#include "clang/EntoSA/PathSensitive/Environment.h"
-#include "clang/EntoSA/PathSensitive/Store.h"
-#include "clang/EntoSA/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableMap.h"
 #include "llvm/Support/Casting.h"
similarity index 99%
rename from include/clang/EntoSA/PathSensitive/MemRegion.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/MemRegion.h
index c9c72ab33edccc521139001a06da8e915f56b007..33779a9fd5276051e6f24a70bd647bcd737e6ed6 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclObjC.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/ADT/FoldingSet.h"
similarity index 97%
rename from include/clang/EntoSA/PathSensitive/SValBuilder.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/SValBuilder.h
index f4c168dc0bba3e27bf25ed064a5b662924a5709a..0705510ccd4f2aa8707a60d464e13d6582a68480 100644 (file)
@@ -17,9 +17,9 @@
 
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
-#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
 
 namespace clang {
 
similarity index 99%
rename from include/clang/EntoSA/PathSensitive/SVals.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/SVals.h
index acbf1d441381277bbaaba593e4b84d4d58e8e855..d4d846954e8b7936983324166747bc93b099973c 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef LLVM_CLANG_GR_RVALUE_H
 #define LLVM_CLANG_GR_RVALUE_H
 
-#include "clang/EntoSA/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/ADT/ImmutableList.h"
 
similarity index 98%
rename from include/clang/EntoSA/PathSensitive/Store.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/Store.h
index 83b113834ec4f13909555323a27bb7aeecfd1409..c48f129febee868b99696380fac58ca362e188be 100644 (file)
@@ -14,8 +14,8 @@
 #ifndef LLVM_CLANG_GR_STORE_H
 #define LLVM_CLANG_GR_STORE_H
 
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
-#include "clang/EntoSA/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/Optional.h"
 
similarity index 98%
rename from include/clang/EntoSA/PathSensitive/SubEngine.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/SubEngine.h
index bddd5e950f38692fbf9e9e25cf63fba4ca625628..8672bd1a02a853c4210e2f1993e983f5f3ce5a97 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef LLVM_CLANG_GR_SUBENGINE_H
 #define LLVM_CLANG_GR_SUBENGINE_H
 
-#include "clang/EntoSA/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
 
 namespace clang {
 
similarity index 96%
rename from include/clang/EntoSA/PathSensitive/TransferFuncs.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/TransferFuncs.h
index ac5b4a6d176e1dfe285e66ace7163cc00c4c0efa..22e3a4d3c0ec83116cd88c2a1d9c6bf9eb074d69 100644 (file)
@@ -15,8 +15,8 @@
 #ifndef LLVM_CLANG_GR_TRANSFERFUNCS
 #define LLVM_CLANG_GR_TRANSFERFUNCS
 
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
 #include <vector>
 
 namespace clang {
similarity index 97%
rename from include/clang/EntoSA/PathSensitive/WorkList.h
rename to include/clang/StaticAnalyzer/EntoSA/PathSensitive/WorkList.h
index 6f98587235f0b7c39f5e182b5c7f3189e7a14c37..be909061cd320fcc6a51b3e28c771973eff71204 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef LLVM_CLANG_GR_WORKLIST
 #define LLVM_CLANG_GR_WORKLIST
 
-#include "clang/EntoSA/PathSensitive/BlockCounter.h"
+#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
 #include <cstddef>
 
 namespace clang {
diff --git a/include/clang/StaticAnalyzer/FrontendActions.h b/include/clang/StaticAnalyzer/FrontendActions.h
new file mode 100644 (file)
index 0000000..e3867a2
--- /dev/null
@@ -0,0 +1,33 @@
+//===-- FrontendActions.h - Useful Frontend Actions -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_FRONTENDACTIONS_H
+#define LLVM_CLANG_GR_FRONTENDACTIONS_H
+
+#include "clang/Frontend/FrontendAction.h"
+
+namespace clang {
+
+namespace ento {
+
+//===----------------------------------------------------------------------===//
+// AST Consumer Actions
+//===----------------------------------------------------------------------===//
+
+class AnalysisAction : public ASTFrontendAction {
+protected:
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile);
+};
+
+} // end GR namespace
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/ManagerRegistry.h b/include/clang/StaticAnalyzer/ManagerRegistry.h
new file mode 100644 (file)
index 0000000..1b84980
--- /dev/null
@@ -0,0 +1,58 @@
+//===-- ManagerRegistry.h - Pluggable analyzer module registry --*- 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 ManagerRegistry and Register* classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_MANAGER_REGISTRY_H
+#define LLVM_CLANG_GR_MANAGER_REGISTRY_H
+
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+
+namespace clang {
+
+namespace ento {
+
+/// ManagerRegistry - This class records manager creators registered at
+/// runtime. The information is communicated to AnalysisManager through static
+/// members. Better design is expected.
+
+class ManagerRegistry {
+public:
+  static StoreManagerCreator StoreMgrCreator;
+  static ConstraintManagerCreator ConstraintMgrCreator;
+};
+
+/// RegisterConstraintManager - This class is used to setup the constraint
+/// manager of the static analyzer. The constructor takes a creator function
+/// pointer for creating the constraint manager.
+///
+/// It is used like this:
+///
+/// class MyConstraintManager {};
+/// ConstraintManager* CreateMyConstraintManager(GRStateManager& statemgr) {
+///  return new MyConstraintManager(statemgr);
+/// }
+/// RegisterConstraintManager X(CreateMyConstraintManager);
+
+class RegisterConstraintManager {
+public:
+  RegisterConstraintManager(ConstraintManagerCreator CMC) {
+    assert(ManagerRegistry::ConstraintMgrCreator == 0
+           && "ConstraintMgrCreator already set!");
+    ManagerRegistry::ConstraintMgrCreator = CMC;
+  }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathDiagnosticClients.h b/include/clang/StaticAnalyzer/PathDiagnosticClients.h
new file mode 100644 (file)
index 0000000..2713e31
--- /dev/null
@@ -0,0 +1,42 @@
+//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- 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 interface to create different path diagostic clients.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H
+#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLiENTS_H
+
+#include <string>
+
+namespace clang {
+
+class Preprocessor;
+
+namespace ento {
+
+class PathDiagnosticClient;
+
+PathDiagnosticClient*
+createHTMLDiagnosticClient(const std::string& prefix, const Preprocessor &PP);
+
+PathDiagnosticClient*
+createPlistDiagnosticClient(const std::string& prefix, const Preprocessor &PP,
+                            PathDiagnosticClient *SubPD = 0);
+
+PathDiagnosticClient*
+createTextPathDiagnosticClient(const std::string& prefix,
+                               const Preprocessor &PP);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/PathSensitive/AnalysisManager.h
new file mode 100644 (file)
index 0000000..ba86ed8
--- /dev/null
@@ -0,0 +1,208 @@
+//== AnalysisManager.h - Path sensitive analysis data manager ------*- 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 AnalysisManager class that manages the data and policy
+// for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_ANALYSISMANAGER_H
+#define LLVM_CLANG_GR_ANALYSISMANAGER_H
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+
+namespace clang {
+
+namespace idx { 
+  class Indexer;
+  class TranslationUnit; 
+}
+
+namespace ento {
+
+class AnalysisManager : public BugReporterData {
+  AnalysisContextManager AnaCtxMgr;
+  LocationContextManager LocCtxMgr;
+
+  ASTContext &Ctx;
+  Diagnostic &Diags;
+  const LangOptions &LangInfo;
+
+  llvm::OwningPtr<PathDiagnosticClient> PD;
+
+  // Configurable components creators.
+  StoreManagerCreator CreateStoreMgr;
+  ConstraintManagerCreator CreateConstraintMgr;
+
+  /// \brief Provide function definitions in other translation units. This is
+  /// NULL if we don't have multiple translation units. AnalysisManager does
+  /// not own the Indexer.
+  idx::Indexer *Idxer;
+
+  enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+
+  // The maximum number of exploded nodes the analyzer will generate.
+  unsigned MaxNodes;
+
+  // The maximum number of times the analyzer visit a block.
+  unsigned MaxVisit;
+
+  bool VisualizeEGDot;
+  bool VisualizeEGUbi;
+  bool PurgeDead;
+
+  /// EargerlyAssume - A flag indicating how the engine should handle
+  //   expressions such as: 'x = (y != 0)'.  When this flag is true then
+  //   the subexpression 'y != 0' will be eagerly assumed to be true or false,
+  //   thus evaluating it to the integers 0 or 1 respectively.  The upside
+  //   is that this can increase analysis precision until we have a better way
+  //   to lazily evaluate such logic.  The downside is that it eagerly
+  //   bifurcates paths.
+  bool EagerlyAssume;
+  bool TrimGraph;
+  bool InlineCall;
+
+public:
+  AnalysisManager(ASTContext &ctx, Diagnostic &diags, 
+                  const LangOptions &lang, PathDiagnosticClient *pd,
+                  StoreManagerCreator storemgr,
+                  ConstraintManagerCreator constraintmgr, 
+                  idx::Indexer *idxer,
+                  unsigned maxnodes, unsigned maxvisit,
+                  bool vizdot, bool vizubi, bool purge, bool eager, bool trim,
+                  bool inlinecall, bool useUnoptimizedCFG,
+                  bool addImplicitDtors, bool addInitializers)
+
+    : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, addInitializers),
+      Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
+      CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),Idxer(idxer),
+      AScope(ScopeDecl), MaxNodes(maxnodes), MaxVisit(maxvisit),
+      VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
+      EagerlyAssume(eager), TrimGraph(trim), InlineCall(inlinecall) {}
+  
+  ~AnalysisManager() { FlushDiagnostics(); }
+  
+  void ClearContexts() {
+    LocCtxMgr.clear();
+    AnaCtxMgr.clear();
+  }
+  
+  AnalysisContextManager& getAnalysisContextManager() {
+    return AnaCtxMgr;
+  }
+
+  StoreManagerCreator getStoreManagerCreator() {
+    return CreateStoreMgr;
+  }
+
+  ConstraintManagerCreator getConstraintManagerCreator() {
+    return CreateConstraintMgr;
+  }
+
+  idx::Indexer *getIndexer() const { return Idxer; }
+
+  virtual ASTContext &getASTContext() {
+    return Ctx;
+  }
+
+  virtual SourceManager &getSourceManager() {
+    return getASTContext().getSourceManager();
+  }
+
+  virtual Diagnostic &getDiagnostic() {
+    return Diags;
+  }
+
+  const LangOptions &getLangOptions() const {
+    return LangInfo;
+  }
+
+  virtual PathDiagnosticClient *getPathDiagnosticClient() {
+    return PD.get();
+  }
+  
+  void FlushDiagnostics() {
+    if (PD.get())
+      PD->FlushDiagnostics();
+  }
+
+  unsigned getMaxNodes() const { return MaxNodes; }
+
+  unsigned getMaxVisit() const { return MaxVisit; }
+
+  bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
+
+  bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
+
+  bool shouldVisualize() const {
+    return VisualizeEGDot || VisualizeEGUbi;
+  }
+
+  bool shouldTrimGraph() const { return TrimGraph; }
+
+  bool shouldPurgeDead() const { return PurgeDead; }
+
+  bool shouldEagerlyAssume() const { return EagerlyAssume; }
+
+  bool shouldInlineCall() const { return InlineCall; }
+
+  bool hasIndexer() const { return Idxer != 0; }
+
+  AnalysisContext *getAnalysisContextInAnotherTU(const Decl *D);
+
+  CFG *getCFG(Decl const *D) {
+    return AnaCtxMgr.getContext(D)->getCFG();
+  }
+
+  LiveVariables *getLiveVariables(Decl const *D) {
+    return AnaCtxMgr.getContext(D)->getLiveVariables();
+  }
+
+  ParentMap &getParentMap(Decl const *D) {
+    return AnaCtxMgr.getContext(D)->getParentMap();
+  }
+
+  AnalysisContext *getAnalysisContext(const Decl *D) {
+    return AnaCtxMgr.getContext(D);
+  }
+
+  AnalysisContext *getAnalysisContext(const Decl *D, idx::TranslationUnit *TU) {
+    return AnaCtxMgr.getContext(D, TU);
+  }
+
+  const StackFrameContext *getStackFrame(AnalysisContext *Ctx,
+                                         LocationContext const *Parent,
+                                         const Stmt *S,
+                                         const CFGBlock *Blk, unsigned Idx) {
+    return LocCtxMgr.getStackFrame(Ctx, Parent, S, Blk, Idx);
+  }
+
+  // Get the top level stack frame.
+  const StackFrameContext *getStackFrame(Decl const *D, 
+                                         idx::TranslationUnit *TU) {
+    return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D, TU), 0, 0, 0, 0);
+  }
+
+  // Get a stack frame with parent.
+  StackFrameContext const *getStackFrame(const Decl *D, 
+                                         LocationContext const *Parent,
+                                         const Stmt *S,
+                                         const CFGBlock *Blk, unsigned Idx) {
+    return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S,
+                                   Blk,Idx);
+  }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h
new file mode 100644 (file)
index 0000000..4cac8b6
--- /dev/null
@@ -0,0 +1,201 @@
+//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- 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 BasicValueFactory, a class that manages the lifetime
+//  of APSInt objects and symbolic constraints used by ExprEngine
+//  and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
+#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
+
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ImmutableList.h"
+
+namespace clang {
+
+namespace ento {
+
+  class GRState;
+
+class CompoundValData : public llvm::FoldingSetNode {
+  QualType T;
+  llvm::ImmutableList<SVal> L;
+
+public:
+  CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
+    : T(t), L(l) {}
+
+  typedef llvm::ImmutableList<SVal>::iterator iterator;
+  iterator begin() const { return L.begin(); }
+  iterator end() const { return L.end(); }
+
+  static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
+                      llvm::ImmutableList<SVal> L);
+
+  void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
+};
+
+class LazyCompoundValData : public llvm::FoldingSetNode {
+  const void *store;
+  const TypedRegion *region;
+public:
+  LazyCompoundValData(const void *st, const TypedRegion *r)
+    : store(st), region(r) {}
+
+  const void *getStore() const { return store; }
+  const TypedRegion *getRegion() const { return region; }
+
+  static void Profile(llvm::FoldingSetNodeID& ID, const void *store,
+                      const TypedRegion *region);
+
+  void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
+};
+
+class BasicValueFactory {
+  typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
+          APSIntSetTy;
+
+  ASTContext& Ctx;
+  llvm::BumpPtrAllocator& BPAlloc;
+
+  APSIntSetTy   APSIntSet;
+  void*         PersistentSVals;
+  void*         PersistentSValPairs;
+
+  llvm::ImmutableList<SVal>::Factory SValListFactory;
+  llvm::FoldingSet<CompoundValData>  CompoundValDataSet;
+  llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
+
+public:
+  BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
+  : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
+    SValListFactory(Alloc) {}
+
+  ~BasicValueFactory();
+
+  ASTContext& getContext() const { return Ctx; }
+
+  const llvm::APSInt& getValue(const llvm::APSInt& X);
+  const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
+  const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
+  const llvm::APSInt& getValue(uint64_t X, QualType T);
+
+  /// Convert - Create a new persistent APSInt with the same value as 'From'
+  ///  but with the bitwidth and signedness of 'To'.
+  const llvm::APSInt &Convert(const llvm::APSInt& To,
+                              const llvm::APSInt& From) {
+
+    if (To.isUnsigned() == From.isUnsigned() &&
+        To.getBitWidth() == From.getBitWidth())
+      return From;
+
+    return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned());
+  }
+  
+  const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
+    assert(T->isIntegerType() || Loc::IsLocType(T));
+    unsigned bitwidth = Ctx.getTypeSize(T);
+    bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+    
+    if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
+      return From;
+    
+    return getValue(From.getSExtValue(), bitwidth, isUnsigned);
+  }
+
+  const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
+    QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
+    return getValue(X, T);
+  }
+
+  inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
+    return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
+  }
+
+  inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
+    return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
+  }
+
+  inline const llvm::APSInt& getMaxValue(QualType T) {
+    assert(T->isIntegerType() || Loc::IsLocType(T));
+    bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+    return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
+  }
+
+  inline const llvm::APSInt& getMinValue(QualType T) {
+    assert(T->isIntegerType() || Loc::IsLocType(T));
+    bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+    return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
+  }
+
+  inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
+    llvm::APSInt X = V;
+    ++X;
+    return getValue(X);
+  }
+
+  inline const llvm::APSInt& Sub1(const llvm::APSInt& V) {
+    llvm::APSInt X = V;
+    --X;
+    return getValue(X);
+  }
+
+  inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
+    return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+  }
+
+  inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
+    return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+  }
+
+  inline const llvm::APSInt& getTruthValue(bool b, QualType T) {
+    return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false);
+  }
+
+  inline const llvm::APSInt& getTruthValue(bool b) {
+    return getTruthValue(b, Ctx.IntTy);
+  }
+
+  const CompoundValData *getCompoundValData(QualType T,
+                                            llvm::ImmutableList<SVal> Vals);
+
+  const LazyCompoundValData *getLazyCompoundValData(const void *store,
+                                                    const TypedRegion *region);
+
+  llvm::ImmutableList<SVal> getEmptySValList() {
+    return SValListFactory.getEmptyList();
+  }
+
+  llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
+    return SValListFactory.add(X, L);
+  }
+
+  const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op,
+                                     const llvm::APSInt& V1,
+                                     const llvm::APSInt& V2);
+
+  const std::pair<SVal, uintptr_t>&
+  getPersistentSValWithData(const SVal& V, uintptr_t Data);
+
+  const std::pair<SVal, SVal>&
+  getPersistentSValPair(const SVal& V1, const SVal& V2);
+
+  const SVal* getPersistentSVal(SVal X);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/BlockCounter.h b/include/clang/StaticAnalyzer/PathSensitive/BlockCounter.h
new file mode 100644 (file)
index 0000000..7d0fdfb
--- /dev/null
@@ -0,0 +1,59 @@
+//==- BlockCounter.h - ADT for counting block visits ---------------*- 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 BlockCounter, an abstract data type used to count
+//  the number of times a given block has been visited along a path
+//  analyzed by CoreEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_BLOCKCOUNTER
+#define LLVM_CLANG_GR_BLOCKCOUNTER
+
+namespace llvm {
+  class BumpPtrAllocator;
+}
+
+namespace clang {
+
+class StackFrameContext;
+
+namespace ento {
+
+class BlockCounter {
+  void* Data;
+
+  BlockCounter(void* D) : Data(D) {}
+
+public:
+  BlockCounter() : Data(0) {}
+
+  unsigned getNumVisited(const StackFrameContext *CallSite, 
+                         unsigned BlockID) const;
+
+  class Factory {
+    void* F;
+  public:
+    Factory(llvm::BumpPtrAllocator& Alloc);
+    ~Factory();
+
+    BlockCounter GetEmptyCounter();
+    BlockCounter IncrementCount(BlockCounter BC, 
+                                  const StackFrameContext *CallSite,
+                                  unsigned BlockID);
+  };
+
+  friend class Factory;
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/PathSensitive/Checker.h
new file mode 100644 (file)
index 0000000..b2103a2
--- /dev/null
@@ -0,0 +1,309 @@
+//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating
+//  domain-specific checks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_CHECKER
+#define LLVM_CLANG_GR_CHECKER
+
+#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+//===----------------------------------------------------------------------===//
+// Checker interface.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+
+namespace ento {
+
+class CheckerContext {
+  ExplodedNodeSet &Dst;
+  StmtNodeBuilder &B;
+  ExprEngine &Eng;
+  ExplodedNode *Pred;
+  SaveAndRestore<bool> OldSink;
+  SaveAndRestore<const void*> OldTag;
+  SaveAndRestore<ProgramPoint::Kind> OldPointKind;
+  SaveOr OldHasGen;
+  const GRState *ST;
+  const Stmt *statement;
+  const unsigned size;
+public:
+  bool *respondsToCallback;
+public:
+  CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder,
+                 ExprEngine &eng, ExplodedNode *pred,
+                 const void *tag, ProgramPoint::Kind K,
+                 bool *respondsToCB = 0,
+                 const Stmt *stmt = 0, const GRState *st = 0)
+    : Dst(dst), B(builder), Eng(eng), Pred(pred),
+      OldSink(B.BuildSinks),
+      OldTag(B.Tag, tag),
+      OldPointKind(B.PointKind, K),
+      OldHasGen(B.HasGeneratedNode),
+      ST(st), statement(stmt), size(Dst.size()),
+      respondsToCallback(respondsToCB) {}
+
+  ~CheckerContext();
+
+  ExprEngine &getEngine() {
+    return Eng;
+  }
+
+  AnalysisManager &getAnalysisManager() {
+    return Eng.getAnalysisManager();
+  }
+
+  ConstraintManager &getConstraintManager() {
+    return Eng.getConstraintManager();
+  }
+
+  StoreManager &getStoreManager() {
+    return Eng.getStoreManager();
+  }
+
+  ExplodedNodeSet &getNodeSet() { return Dst; }
+  StmtNodeBuilder &getNodeBuilder() { return B; }
+  ExplodedNode *&getPredecessor() { return Pred; }
+  const GRState *getState() { return ST ? ST : B.GetState(Pred); }
+
+  ASTContext &getASTContext() {
+    return Eng.getContext();
+  }
+  
+  BugReporter &getBugReporter() {
+    return Eng.getBugReporter();
+  }
+  
+  SourceManager &getSourceManager() {
+    return getBugReporter().getSourceManager();
+  }
+
+  SValBuilder &getSValBuilder() {
+    return Eng.getSValBuilder();
+  }
+
+  ExplodedNode *generateNode(bool autoTransition = true) {
+    assert(statement && "Only transitions with statements currently supported");
+    ExplodedNode *N = generateNodeImpl(statement, getState(), false);
+    if (N && autoTransition)
+      Dst.Add(N);
+    return N;
+  }
+  
+  ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
+                             bool autoTransition = true) {
+    assert(state);
+    ExplodedNode *N = generateNodeImpl(stmt, state, false);
+    if (N && autoTransition)
+      addTransition(N);
+    return N;
+  }
+
+  ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
+                             bool autoTransition = true) {
+   assert(statement && "Only transitions with statements currently supported");
+    ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
+    if (N && autoTransition)
+      addTransition(N);
+    return N;
+  }
+
+  ExplodedNode *generateNode(const GRState *state, bool autoTransition = true) {
+    assert(statement && "Only transitions with statements currently supported");
+    ExplodedNode *N = generateNodeImpl(statement, state, false);
+    if (N && autoTransition)
+      addTransition(N);
+    return N;
+  }
+
+  ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
+    return generateNodeImpl(stmt, state ? state : getState(), true);
+  }
+  
+  ExplodedNode *generateSink(const GRState *state = 0) {
+    assert(statement && "Only transitions with statements currently supported");
+    return generateNodeImpl(statement, state ? state : getState(), true);
+  }
+
+  void addTransition(ExplodedNode *node) {
+    Dst.Add(node);
+  }
+  
+  void addTransition(const GRState *state) {
+    assert(state);
+    // If the 'state' is not new, we need to check if the cached state 'ST'
+    // is new.
+    if (state != getState() || (ST && ST != B.GetState(Pred)))
+      // state is new or equals to ST.
+      generateNode(state, true);
+    else
+      Dst.Add(Pred);
+  }
+
+  // Generate a node with a new program point different from the one that will
+  // be created by the StmtNodeBuilder.
+  void addTransition(const GRState *state, ProgramPoint Loc) {
+    ExplodedNode *N = B.generateNode(Loc, state, Pred);
+    if (N)
+      addTransition(N);
+  }
+
+  void EmitReport(BugReport *R) {
+    Eng.getBugReporter().EmitReport(R);
+  }
+
+  AnalysisContext *getCurrentAnalysisContext() const {
+    return Pred->getLocationContext()->getAnalysisContext();
+  }
+
+private:
+  ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
+                             bool markAsSink) {
+    ExplodedNode *node = B.generateNode(stmt, state, Pred);
+    if (markAsSink && node)
+      node->markAsSink();
+    return node;
+  }
+
+  ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
+                                 ExplodedNode *pred, bool markAsSink) {
+   ExplodedNode *node = B.generateNode(stmt, state, pred);
+    if (markAsSink && node)
+      node->markAsSink();
+    return node;
+  }
+};
+
+class Checker {
+private:
+  friend class ExprEngine;
+
+  // FIXME: Remove the 'tag' option.
+  void GR_Visit(ExplodedNodeSet &Dst,
+                StmtNodeBuilder &Builder,
+                ExprEngine &Eng,
+                const Stmt *S,
+                ExplodedNode *Pred, void *tag, bool isPrevisit,
+                bool& respondsToCallback) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag,
+                     isPrevisit ? ProgramPoint::PreStmtKind :
+                     ProgramPoint::PostStmtKind, &respondsToCallback, S);
+    if (isPrevisit)
+      _PreVisit(C, S);
+    else
+      _PostVisit(C, S);
+  }
+
+  bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
+                          ExprEngine &Eng, const ObjCMessageExpr *ME,
+                          ExplodedNode *Pred, const GRState *state, void *tag) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+                     0, ME, state);
+    return evalNilReceiver(C, ME);
+  }
+
+  bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
+                       ExprEngine &Eng, const CallExpr *CE,
+                       ExplodedNode *Pred, void *tag) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+                     0, CE);
+    return evalCallExpr(C, CE);
+  }
+
+  // FIXME: Remove the 'tag' option.
+  void GR_VisitBind(ExplodedNodeSet &Dst,
+                    StmtNodeBuilder &Builder, ExprEngine &Eng,
+                    const Stmt *StoreE, ExplodedNode *Pred, void *tag, 
+                    SVal location, SVal val,
+                    bool isPrevisit) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag,
+                     isPrevisit ? ProgramPoint::PreStmtKind :
+                     ProgramPoint::PostStmtKind, 0, StoreE);
+    assert(isPrevisit && "Only previsit supported for now.");
+    PreVisitBind(C, StoreE, location, val);
+  }
+  
+  // FIXME: Remove the 'tag' option.
+  void GR_visitLocation(ExplodedNodeSet &Dst,
+                        StmtNodeBuilder &Builder,
+                        ExprEngine &Eng,
+                        const Stmt *S,
+                        ExplodedNode *Pred, const GRState *state,
+                        SVal location,
+                        void *tag, bool isLoad) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag,
+                     isLoad ? ProgramPoint::PreLoadKind :
+                     ProgramPoint::PreStoreKind, 0, S, state);
+    visitLocation(C, S, location);
+  }
+
+  void GR_evalDeadSymbols(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
+                          ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
+                          SymbolReaper &SymReaper, void *tag) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag, 
+                     ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
+    evalDeadSymbols(C, SymReaper);
+  }
+
+public:
+  virtual ~Checker();
+  virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
+  virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
+  virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location) {}
+  virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
+                            SVal location, SVal val) {}
+  virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {}
+  virtual void evalEndPath(EndPathNodeBuilder &B, void *tag,
+                           ExprEngine &Eng) {}
+
+  virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {}
+
+  virtual void VisitBranchCondition(BranchNodeBuilder &Builder,
+                                    ExprEngine &Eng,
+                                    const Stmt *Condition, void *tag) {}
+
+  virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
+    return false;
+  }
+
+  virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+    return false;
+  }
+
+  virtual const GRState *evalAssume(const GRState *state, SVal Cond, 
+                                    bool Assumption, bool *respondsToCallback) {
+    *respondsToCallback = false;
+    return state;
+  }
+
+  virtual bool WantsRegionChangeUpdate(const GRState *state) { return false; }
+
+  virtual const GRState *EvalRegionChanges(const GRState *state,
+                                           const MemRegion * const *Begin,
+                                           const MemRegion * const *End,
+                                           bool *respondsToCallback) {
+    *respondsToCallback = false;
+    return state;
+  }
+
+  virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
+                                ExprEngine &Eng) {}
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
+
diff --git a/include/clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h b/include/clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h
new file mode 100644 (file)
index 0000000..005e0e5
--- /dev/null
@@ -0,0 +1,44 @@
+//== CheckerHelpers.h - Helper functions for checkers ------------*- 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 CheckerVisitor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS
+#define LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS
+
+#include "clang/AST/Stmt.h"
+
+namespace clang {
+
+namespace ento {
+
+bool containsMacro(const Stmt *S);
+bool containsEnum(const Stmt *S);
+bool containsStaticLocal(const Stmt *S);
+bool containsBuiltinOffsetOf(const Stmt *S);
+template <class T> bool containsStmt(const Stmt *S) {
+  if (isa<T>(S))
+      return true;
+
+  for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+      ++I)
+    if (const Stmt *child = *I)
+      if (containsStmt<T>(child))
+        return true;
+
+  return false;
+}
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def b/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def
new file mode 100644 (file)
index 0000000..3ee8071
--- /dev/null
@@ -0,0 +1,43 @@
+//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===//
+//
+//                     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 AST nodes accepted by the CheckerVisitor class.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef PREVISIT
+#define PREVISIT(NODE, FALLBACK)
+#endif
+
+#ifndef POSTVISIT
+#define POSTVISIT(NODE, FALLBACK)
+#endif
+
+PREVISIT(ArraySubscriptExpr, Stmt)
+PREVISIT(BinaryOperator, Stmt)
+PREVISIT(CallExpr, GenericCall)
+PREVISIT(CStyleCastExpr, CastExpr)
+PREVISIT(CXXFunctionalCastExpr, CastExpr)
+PREVISIT(CXXOperatorCallExpr, GenericCall)
+PREVISIT(CXXMemberCallExpr, GenericCall)
+PREVISIT(DeclStmt, Stmt)
+PREVISIT(ImplicitCastExpr, CastExpr)
+PREVISIT(ObjCAtSynchronizedStmt, Stmt)
+PREVISIT(ObjCMessageExpr, Stmt)
+PREVISIT(ReturnStmt, Stmt)
+
+POSTVISIT(BlockExpr, Stmt)
+POSTVISIT(BinaryOperator, Stmt)
+POSTVISIT(CallExpr, GenericCall)
+POSTVISIT(CXXOperatorCallExpr, GenericCall)
+POSTVISIT(CXXMemberCallExpr, GenericCall)
+POSTVISIT(ObjCMessageExpr, Stmt)
+
+#undef PREVISIT
+#undef POSTVISIT
diff --git a/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h b/include/clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h
new file mode 100644 (file)
index 0000000..68677f5
--- /dev/null
@@ -0,0 +1,111 @@
+//== CheckerVisitor.h - Abstract visitor for checkers ------------*- 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 CheckerVisitor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_CHECKERVISITOR
+#define LLVM_CLANG_GR_CHECKERVISITOR
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+
+namespace clang {
+
+namespace ento {
+
+//===----------------------------------------------------------------------===//
+// Checker visitor interface.  Used by subclasses of Checker to specify their
+// own checker visitor logic.
+//===----------------------------------------------------------------------===//
+
+/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses.
+/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
+template<typename ImplClass>
+class CheckerVisitor : public Checker {
+public:
+  virtual void _PreVisit(CheckerContext &C, const Stmt *S) {
+    PreVisit(C, S);
+  }
+  
+  virtual void _PostVisit(CheckerContext &C, const Stmt *S) {
+    PostVisit(C, S);
+  }
+
+  void PreVisit(CheckerContext &C, const Stmt *S) {
+    switch (S->getStmtClass()) {
+      default:
+        assert(false && "Unsupport statement.");
+        return;
+      case Stmt::CompoundAssignOperatorClass:
+        static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C,
+                                         static_cast<const BinaryOperator*>(S));
+        break;
+
+#define PREVISIT(NAME, FALLBACK) \
+case Stmt::NAME ## Class:\
+static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
+break;
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
+    }
+  }
+  
+  void PostVisit(CheckerContext &C, const Stmt *S) {
+    switch (S->getStmtClass()) {
+      default:
+        assert(false && "Unsupport statement.");
+        return;
+      case Stmt::CompoundAssignOperatorClass:
+        static_cast<ImplClass*>(this)->PostVisitBinaryOperator(C,
+                                         static_cast<const BinaryOperator*>(S));
+        break;
+
+#define POSTVISIT(NAME, FALLBACK) \
+case Stmt::NAME ## Class:\
+static_cast<ImplClass*>(this)->\
+PostVisit ## NAME(C,static_cast<const NAME*>(S));\
+break;
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
+    }
+  }
+
+  void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE) {
+    static_cast<ImplClass*>(this)->PreVisitStmt(C, CE);
+  }
+  void PostVisitGenericCall(CheckerContext &C, const CallExpr *CE) {
+    static_cast<ImplClass*>(this)->PostVisitStmt(C, CE);
+  }
+
+  void PreVisitStmt(CheckerContext &C, const Stmt *S) {
+    *C.respondsToCallback = false;
+  }
+
+  void PostVisitStmt(CheckerContext &C, const Stmt *S) {
+    *C.respondsToCallback = false;
+  }
+
+  void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) {
+    static_cast<ImplClass*>(this)->PreVisitStmt(C, E);
+  }
+  
+#define PREVISIT(NAME, FALLBACK) \
+void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\
+  static_cast<ImplClass*>(this)->PreVisit ## FALLBACK(C, S);\
+}
+#define POSTVISIT(NAME, FALLBACK) \
+void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
+  static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
+}
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.def"
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/PathSensitive/ConstraintManager.h
new file mode 100644 (file)
index 0000000..81f4558
--- /dev/null
@@ -0,0 +1,76 @@
+//== ConstraintManager.h - Constraints on 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 defined the interface to manage constraints on symbolic values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
+#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
+
+// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+
+namespace llvm {
+class APSInt;
+}
+
+namespace clang {
+
+namespace ento {
+
+class GRState;
+class GRStateManager;
+class SubEngine;
+class SVal;
+
+class ConstraintManager {
+public:
+  virtual ~ConstraintManager();
+  virtual const GRState *assume(const GRState *state, DefinedSVal Cond,
+                                bool Assumption) = 0;
+
+  std::pair<const GRState*, const GRState*> assumeDual(const GRState *state,
+                                                       DefinedSVal Cond) {
+    return std::make_pair(assume(state, Cond, true),
+                          assume(state, Cond, false));
+  }
+
+  virtual const llvm::APSInt* getSymVal(const GRState *state,
+                                        SymbolRef sym) const = 0;
+
+  virtual bool isEqual(const GRState *state, SymbolRef sym,
+                       const llvm::APSInt& V) const = 0;
+
+  virtual const GRState *RemoveDeadBindings(const GRState *state,
+                                            SymbolReaper& SymReaper) = 0;
+
+  virtual void print(const GRState *state, llvm::raw_ostream& Out,
+                     const char* nl, const char *sep) = 0;
+
+  virtual void EndPath(const GRState *state) {}
+
+  /// canReasonAbout - Not all ConstraintManagers can accurately reason about
+  ///  all SVal values.  This method returns true if the ConstraintManager can
+  ///  reasonably handle a given SVal value.  This is typically queried by
+  ///  ExprEngine to determine if the value should be replaced with a
+  ///  conjured symbolic value in order to recover some precision.
+  virtual bool canReasonAbout(SVal X) const = 0;
+};
+
+ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
+                                                SubEngine &subengine);
+ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
+                                                SubEngine &subengine);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/PathSensitive/CoreEngine.h
new file mode 100644 (file)
index 0000000..3d63982
--- /dev/null
@@ -0,0 +1,542 @@
+//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- 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 a generic engine for intraprocedural, path-sensitive,
+//  dataflow analysis via graph reachability.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_COREENGINE
+#define LLVM_CLANG_GR_COREENGINE
+
+#include "clang/AST/Expr.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/WorkList.h"
+#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
+#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+
+namespace ento {
+
+//===----------------------------------------------------------------------===//
+/// CoreEngine - Implements the core logic of the graph-reachability
+///   analysis. It traverses the CFG and generates the ExplodedGraph.
+///   Program "states" are treated as opaque void pointers.
+///   The template class CoreEngine (which subclasses CoreEngine)
+///   provides the matching component to the engine that knows the actual types
+///   for states.  Note that this engine only dispatches to transfer functions
+///   at the statement and block-level.  The analyses themselves must implement
+///   any transfer function logic and the sub-expression level (if any).
+class CoreEngine {
+  friend class StmtNodeBuilder;
+  friend class BranchNodeBuilder;
+  friend class IndirectGotoNodeBuilder;
+  friend class SwitchNodeBuilder;
+  friend class EndPathNodeBuilder;
+  friend class CallEnterNodeBuilder;
+  friend class CallExitNodeBuilder;
+
+public:
+  typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
+            BlocksAborted;
+private:
+
+  SubEngine& SubEng;
+
+  /// G - The simulation graph.  Each node is a (location,state) pair.
+  llvm::OwningPtr<ExplodedGraph> G;
+
+  /// WList - A set of queued nodes that need to be processed by the
+  ///  worklist algorithm.  It is up to the implementation of WList to decide
+  ///  the order that nodes are processed.
+  WorkList* WList;
+
+  /// BCounterFactory - A factory object for created BlockCounter objects.
+  ///   These are used to record for key nodes in the ExplodedGraph the
+  ///   number of times different CFGBlocks have been visited along a path.
+  BlockCounter::Factory BCounterFactory;
+
+  /// The locations where we stopped doing work because we visited a location
+  ///  too many times.
+  BlocksAborted blocksAborted;
+
+  void generateNode(const ProgramPoint& Loc, const GRState* State,
+                    ExplodedNode* Pred);
+
+  void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
+  void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
+  void HandleBlockExit(const CFGBlock* B, ExplodedNode* Pred);
+  void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred);
+
+  void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B,
+                    ExplodedNode* Pred);
+  void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
+                       unsigned Index, ExplodedNode *Pred);
+  void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
+
+  /// Get the initial state from the subengine.
+  const GRState* getInitialState(const LocationContext *InitLoc) {
+    return SubEng.getInitialState(InitLoc);
+  }
+
+  void ProcessEndPath(EndPathNodeBuilder& Builder) {
+    SubEng.ProcessEndPath(Builder);
+  }
+
+  void ProcessElement(const CFGElement E, StmtNodeBuilder& Builder) {
+    SubEng.ProcessElement(E, Builder);
+  }
+
+  bool ProcessBlockEntrance(const CFGBlock* Blk, const ExplodedNode *Pred,
+                            BlockCounter BC) {
+    return SubEng.ProcessBlockEntrance(Blk, Pred, BC);
+  }
+
+
+  void ProcessBranch(const Stmt* Condition, const Stmt* Terminator,
+                     BranchNodeBuilder& Builder) {
+    SubEng.ProcessBranch(Condition, Terminator, Builder);
+  }
+
+
+  void ProcessIndirectGoto(IndirectGotoNodeBuilder& Builder) {
+    SubEng.ProcessIndirectGoto(Builder);
+  }
+
+
+  void ProcessSwitch(SwitchNodeBuilder& Builder) {
+    SubEng.ProcessSwitch(Builder);
+  }
+
+  void ProcessCallEnter(CallEnterNodeBuilder &Builder) {
+    SubEng.ProcessCallEnter(Builder);
+  }
+
+  void ProcessCallExit(CallExitNodeBuilder &Builder) {
+    SubEng.ProcessCallExit(Builder);
+  }
+
+private:
+  CoreEngine(const CoreEngine&); // Do not implement.
+  CoreEngine& operator=(const CoreEngine&);
+
+public:
+  /// Construct a CoreEngine object to analyze the provided CFG using
+  ///  a DFS exploration of the exploded graph.
+  CoreEngine(SubEngine& subengine)
+    : SubEng(subengine), G(new ExplodedGraph()),
+      WList(WorkList::MakeBFS()),
+      BCounterFactory(G->getAllocator()) {}
+
+  /// Construct a CoreEngine object to analyze the provided CFG and to
+  ///  use the provided worklist object to execute the worklist algorithm.
+  ///  The CoreEngine object assumes ownership of 'wlist'.
+  CoreEngine(WorkList* wlist, SubEngine& subengine)
+    : SubEng(subengine), G(new ExplodedGraph()), WList(wlist),
+      BCounterFactory(G->getAllocator()) {}
+
+  ~CoreEngine() {
+    delete WList;
+  }
+
+  /// getGraph - Returns the exploded graph.
+  ExplodedGraph& getGraph() { return *G.get(); }
+
+  /// takeGraph - Returns the exploded graph.  Ownership of the graph is
+  ///  transfered to the caller.
+  ExplodedGraph* takeGraph() { return G.take(); }
+
+  /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
+  ///  steps.  Returns true if there is still simulation state on the worklist.
+  bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
+                       const GRState *InitState);
+  void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+                                       const GRState *InitState, 
+                                       ExplodedNodeSet &Dst);
+
+  // Functions for external checking of whether we have unfinished work
+  bool wasBlockAborted() const { return !blocksAborted.empty(); }
+  bool hasWorkRemaining() const { return wasBlockAborted() || WList->hasWork(); }
+
+  WorkList *getWorkList() const { return WList; }
+
+  BlocksAborted::const_iterator blocks_aborted_begin() const {
+    return blocksAborted.begin();
+  }
+  BlocksAborted::const_iterator blocks_aborted_end() const {
+    return blocksAborted.end();
+  }
+};
+
+class StmtNodeBuilder {
+  CoreEngine& Eng;
+  const CFGBlock& B;
+  const unsigned Idx;
+  ExplodedNode* Pred;
+  GRStateManager& Mgr;
+
+public:
+  bool PurgingDeadSymbols;
+  bool BuildSinks;
+  bool HasGeneratedNode;
+  ProgramPoint::Kind PointKind;
+  const void *Tag;
+
+  const GRState* CleanedState;
+
+
+  typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
+  DeferredTy Deferred;
+
+  void GenerateAutoTransition(ExplodedNode* N);
+
+public:
+  StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N,
+                    CoreEngine* e, GRStateManager &mgr);
+
+  ~StmtNodeBuilder();
+
+  ExplodedNode* getBasePredecessor() const { return Pred; }
+
+  // FIXME: This should not be exposed.
+  WorkList *getWorkList() { return Eng.WList; }
+
+  void SetCleanedState(const GRState* St) {
+    CleanedState = St;
+  }
+
+  BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+  unsigned getCurrentBlockCount() const {
+    return getBlockCounter().getNumVisited(
+                            Pred->getLocationContext()->getCurrentStackFrame(),
+                                           B.getBlockID());
+  }
+
+  ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
+    HasGeneratedNode = true;
+    return generateNodeInternal(PP, St, Pred);
+  }
+
+  ExplodedNode* generateNode(const Stmt *S, const GRState *St,
+                             ExplodedNode *Pred, ProgramPoint::Kind K) {
+    HasGeneratedNode = true;
+
+    if (PurgingDeadSymbols)
+      K = ProgramPoint::PostPurgeDeadSymbolsKind;
+
+    return generateNodeInternal(S, St, Pred, K, Tag);
+  }
+
+  ExplodedNode* generateNode(const Stmt *S, const GRState *St,
+                             ExplodedNode *Pred) {
+    return generateNode(S, St, Pred, PointKind);
+  }
+
+  ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
+                             ExplodedNode* Pred) {
+    HasGeneratedNode = true;
+    return generateNodeInternal(PP, State, Pred);
+  }
+
+  ExplodedNode*
+  generateNodeInternal(const ProgramPoint &PP, const GRState* State,
+                       ExplodedNode* Pred);
+
+  ExplodedNode*
+  generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
+                   ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+                   const void *tag = 0);
+
+  /// getStmt - Return the current block-level expression associated with
+  ///  this builder.
+  const Stmt* getStmt() const { 
+    CFGStmt CS = B[Idx].getAs<CFGStmt>();
+    if (CS)
+      return CS.getStmt();
+    else
+      return 0;
+  }
+
+  /// getBlock - Return the CFGBlock associated with the block-level expression
+  ///  of this builder.
+  const CFGBlock* getBlock() const { return &B; }
+
+  unsigned getIndex() const { return Idx; }
+
+  const GRState* GetState(ExplodedNode* Pred) const {
+    if (Pred == getBasePredecessor())
+      return CleanedState;
+    else
+      return Pred->getState();
+  }
+
+  ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S, 
+                         ExplodedNode* Pred, const GRState* St) {
+    return MakeNode(Dst, S, Pred, St, PointKind);
+  }
+
+  ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,ExplodedNode* Pred,
+                         const GRState* St, ProgramPoint::Kind K);
+
+  ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, const Stmt* S,
+                       ExplodedNode* Pred, const GRState* St) {
+    bool Tmp = BuildSinks;
+    BuildSinks = true;
+    ExplodedNode* N = MakeNode(Dst, S, Pred, St);
+    BuildSinks = Tmp;
+    return N;
+  }
+};
+
+class BranchNodeBuilder {
+  CoreEngine& Eng;
+  const CFGBlock* Src;
+  const CFGBlock* DstT;
+  const CFGBlock* DstF;
+  ExplodedNode* Pred;
+
+  typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
+  DeferredTy Deferred;
+
+  bool GeneratedTrue;
+  bool GeneratedFalse;
+  bool InFeasibleTrue;
+  bool InFeasibleFalse;
+
+public:
+  BranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT, 
+                      const CFGBlock* dstF, ExplodedNode* pred, CoreEngine* e)
+  : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
+    GeneratedTrue(false), GeneratedFalse(false),
+    InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
+
+  ~BranchNodeBuilder();
+
+  ExplodedNode* getPredecessor() const { return Pred; }
+
+  const ExplodedGraph& getGraph() const { return *Eng.G; }
+
+  BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+  ExplodedNode* generateNode(const GRState* State, bool branch);
+
+  const CFGBlock* getTargetBlock(bool branch) const {
+    return branch ? DstT : DstF;
+  }
+
+  void markInfeasible(bool branch) {
+    if (branch)
+      InFeasibleTrue = GeneratedTrue = true;
+    else
+      InFeasibleFalse = GeneratedFalse = true;
+  }
+
+  bool isFeasible(bool branch) {
+    return branch ? !InFeasibleTrue : !InFeasibleFalse;
+  }
+
+  const GRState* getState() const {
+    return getPredecessor()->getState();
+  }
+};
+
+class IndirectGotoNodeBuilder {
+  CoreEngine& Eng;
+  const CFGBlock* Src;
+  const CFGBlock& DispatchBlock;
+  const Expr* E;
+  ExplodedNode* Pred;
+
+public:
+  IndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src, 
+                    const Expr* e, const CFGBlock* dispatch, CoreEngine* eng)
+    : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+
+  class iterator {
+    CFGBlock::const_succ_iterator I;
+
+    friend class IndirectGotoNodeBuilder;
+    iterator(CFGBlock::const_succ_iterator i) : I(i) {}
+  public:
+
+    iterator& operator++() { ++I; return *this; }
+    bool operator!=(const iterator& X) const { return I != X.I; }
+
+    const LabelStmt* getLabel() const {
+      return llvm::cast<LabelStmt>((*I)->getLabel());
+    }
+
+    const CFGBlock*  getBlock() const {
+      return *I;
+    }
+  };
+
+  iterator begin() { return iterator(DispatchBlock.succ_begin()); }
+  iterator end() { return iterator(DispatchBlock.succ_end()); }
+
+  ExplodedNode* generateNode(const iterator& I, const GRState* State,
+                             bool isSink = false);
+
+  const Expr* getTarget() const { return E; }
+
+  const GRState* getState() const { return Pred->State; }
+};
+
+class SwitchNodeBuilder {
+  CoreEngine& Eng;
+  const CFGBlock* Src;
+  const Expr* Condition;
+  ExplodedNode* Pred;
+
+public:
+  SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
+                      const Expr* condition, CoreEngine* eng)
+  : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+
+  class iterator {
+    CFGBlock::const_succ_reverse_iterator I;
+
+    friend class SwitchNodeBuilder;
+    iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
+
+  public:
+    iterator& operator++() { ++I; return *this; }
+    bool operator!=(const iterator &X) const { return I != X.I; }
+    bool operator==(const iterator &X) const { return I == X.I; }
+
+    const CaseStmt* getCase() const {
+      return llvm::cast<CaseStmt>((*I)->getLabel());
+    }
+
+    const CFGBlock* getBlock() const {
+      return *I;
+    }
+  };
+
+  iterator begin() { return iterator(Src->succ_rbegin()+1); }
+  iterator end() { return iterator(Src->succ_rend()); }
+
+  const SwitchStmt *getSwitch() const {
+    return llvm::cast<SwitchStmt>(Src->getTerminator());
+  }
+
+  ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
+
+  ExplodedNode* generateDefaultCaseNode(const GRState* State,
+                                        bool isSink = false);
+
+  const Expr* getCondition() const { return Condition; }
+
+  const GRState* getState() const { return Pred->State; }
+};
+
+class EndPathNodeBuilder {
+  CoreEngine &Eng;
+  const CFGBlock& B;
+  ExplodedNode* Pred;
+
+public:
+  bool HasGeneratedNode;
+
+public:
+  EndPathNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e)
+    : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
+
+  ~EndPathNodeBuilder();
+
+  WorkList &getWorkList() { return *Eng.WList; }
+
+  ExplodedNode* getPredecessor() const { return Pred; }
+
+  BlockCounter getBlockCounter() const {
+    return Eng.WList->getBlockCounter();
+  }
+
+  unsigned getCurrentBlockCount() const {
+    return getBlockCounter().getNumVisited(
+                            Pred->getLocationContext()->getCurrentStackFrame(),
+                                           B.getBlockID());
+  }
+
+  ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
+                             ExplodedNode *P = 0);
+
+  void GenerateCallExitNode(const GRState *state);
+
+  const CFGBlock* getBlock() const { return &B; }
+
+  const GRState* getState() const {
+    return getPredecessor()->getState();
+  }
+};
+
+class CallEnterNodeBuilder {
+  CoreEngine &Eng;
+
+  const ExplodedNode *Pred;
+
+  // The call site. For implicit automatic object dtor, this is the trigger 
+  // statement.
+  const Stmt *CE;
+
+  // The context of the callee.
+  const StackFrameContext *CalleeCtx;
+
+  // The parent block of the CallExpr.
+  const CFGBlock *Block;
+
+  // The CFGBlock index of the CallExpr.
+  unsigned Index;
+
+public:
+  CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred, 
+                         const Stmt *s, const StackFrameContext *callee, 
+                         const CFGBlock *blk, unsigned idx)
+    : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
+
+  const GRState *getState() const { return Pred->getState(); }
+
+  const LocationContext *getLocationContext() const { 
+    return Pred->getLocationContext();
+  }
+
+  const Stmt *getCallExpr() const { return CE; }
+
+  const StackFrameContext *getCalleeContext() const { return CalleeCtx; }
+
+  const CFGBlock *getBlock() const { return Block; }
+
+  unsigned getIndex() const { return Index; }
+
+  void generateNode(const GRState *state);
+};
+
+class CallExitNodeBuilder {
+  CoreEngine &Eng;
+  const ExplodedNode *Pred;
+
+public:
+  CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred)
+    : Eng(eng), Pred(pred) {}
+
+  const ExplodedNode *getPredecessor() const { return Pred; }
+
+  const GRState *getState() const { return Pred->getState(); }
+
+  void generateNode(const GRState *state);
+}; 
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/PathSensitive/Environment.h
new file mode 100644 (file)
index 0000000..8f2ebce
--- /dev/null
@@ -0,0 +1,106 @@
+//== Environment.h - Map from Stmt* to Locations/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 defined the Environment and EnvironmentManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_ENVIRONMENT_H
+#define LLVM_CLANG_GR_ENVIRONMENT_H
+
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+namespace clang {
+
+class LiveVariables;
+
+namespace ento {
+
+class EnvironmentManager;
+class SValBuilder;
+
+/// Environment - An immutable map from Stmts to their current
+///  symbolic values (SVals).
+///
+class Environment {
+private:
+  friend class EnvironmentManager;
+
+  // Type definitions.
+  typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy;
+
+  // Data.
+  BindingsTy ExprBindings;
+
+  Environment(BindingsTy eb)
+    : ExprBindings(eb) {}
+
+  SVal lookupExpr(const Stmt* E) const;
+
+public:
+  typedef BindingsTy::iterator iterator;
+  iterator begin() const { return ExprBindings.begin(); }
+  iterator end() const { return ExprBindings.end(); }
+
+
+  /// GetSVal - Fetches the current binding of the expression in the
+  ///  Environment.
+  SVal getSVal(const Stmt* Ex, SValBuilder& svalBuilder) const;
+
+  /// Profile - Profile the contents of an Environment object for use
+  ///  in a FoldingSet.
+  static void Profile(llvm::FoldingSetNodeID& ID, const Environment* env) {
+    env->ExprBindings.Profile(ID);
+  }
+
+  /// Profile - Used to profile the contents of this object for inclusion
+  ///  in a FoldingSet.
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    Profile(ID, this);
+  }
+
+  bool operator==(const Environment& RHS) const {
+    return ExprBindings == RHS.ExprBindings;
+  }
+};
+
+class EnvironmentManager {
+private:
+  typedef Environment::BindingsTy::Factory FactoryTy;
+  FactoryTy F;
+
+public:
+  EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
+  ~EnvironmentManager() {}
+
+  Environment getInitialEnvironment() {
+    return Environment(F.getEmptyMap());
+  }
+
+  /// Bind the value 'V' to the statement 'S'.
+  Environment bindExpr(Environment Env, const Stmt *S, SVal V,
+                       bool Invalidate);
+  
+  /// Bind the location 'location' and value 'V' to the statement 'S'.  This
+  /// is used when simulating loads/stores.
+  Environment bindExprAndLocation(Environment Env, const Stmt *S, SVal location,
+                                  SVal V);
+
+  Environment RemoveDeadBindings(Environment Env,
+                                 SymbolReaper &SymReaper, const GRState *ST,
+                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h
new file mode 100644 (file)
index 0000000..7f8c4c6
--- /dev/null
@@ -0,0 +1,435 @@
+//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph,
+//  which represent a path-sensitive, intra-procedural "exploded graph."
+//  See "Precise interprocedural dataflow analysis via graph reachability"
+//  by Reps, Horwitz, and Sagiv
+//  (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
+//  exploded graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH
+#define LLVM_CLANG_GR_EXPLODEDGRAPH
+
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/Support/Casting.h"
+#include "clang/Analysis/Support/BumpVector.h"
+
+namespace clang {
+
+class CFG;
+
+namespace ento {
+
+class GRState;
+class ExplodedGraph;
+
+//===----------------------------------------------------------------------===//
+// ExplodedGraph "implementation" classes.  These classes are not typed to
+// contain a specific kind of state.  Typed-specialized versions are defined
+// on top of these classes.
+//===----------------------------------------------------------------------===//
+
+class ExplodedNode : public llvm::FoldingSetNode {
+  friend class ExplodedGraph;
+  friend class CoreEngine;
+  friend class StmtNodeBuilder;
+  friend class BranchNodeBuilder;
+  friend class IndirectGotoNodeBuilder;
+  friend class SwitchNodeBuilder;
+  friend class EndPathNodeBuilder;
+
+  class NodeGroup {
+    enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
+    uintptr_t P;
+
+    unsigned getKind() const {
+      return P & 0x1;
+    }
+
+    void* getPtr() const {
+      assert (!getFlag());
+      return reinterpret_cast<void*>(P & ~Mask);
+    }
+
+    ExplodedNode *getNode() const {
+      return reinterpret_cast<ExplodedNode*>(getPtr());
+    }
+
+  public:
+    NodeGroup() : P(0) {}
+
+    ExplodedNode **begin() const;
+
+    ExplodedNode **end() const;
+
+    unsigned size() const;
+
+    bool empty() const { return (P & ~Mask) == 0; }
+
+    void addNode(ExplodedNode* N, ExplodedGraph &G);
+
+    void setFlag() {
+      assert(P == 0);
+      P = AuxFlag;
+    }
+
+    bool getFlag() const {
+      return P & AuxFlag ? true : false;
+    }
+  };
+
+  /// Location - The program location (within a function body) associated
+  ///  with this node.
+  const ProgramPoint Location;
+
+  /// State - The state associated with this node.
+  const GRState* State;
+
+  /// Preds - The predecessors of this node.
+  NodeGroup Preds;
+
+  /// Succs - The successors of this node.
+  NodeGroup Succs;
+
+public:
+
+  explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
+    : Location(loc), State(state) {}
+
+  /// getLocation - Returns the edge associated with the given node.
+  ProgramPoint getLocation() const { return Location; }
+
+  const LocationContext *getLocationContext() const {
+    return getLocation().getLocationContext();
+  }
+
+  const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
+
+  CFG &getCFG() const { return *getLocationContext()->getCFG(); }
+
+  ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
+
+  LiveVariables &getLiveVariables() const { 
+    return *getLocationContext()->getLiveVariables(); 
+  }
+
+  const GRState* getState() const { return State; }
+
+  template <typename T>
+  const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
+
+  static void Profile(llvm::FoldingSetNodeID &ID,
+                      const ProgramPoint& Loc, const GRState* state) {
+    ID.Add(Loc);
+    ID.AddPointer(state);
+  }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    Profile(ID, getLocation(), getState());
+  }
+
+  /// addPredeccessor - Adds a predecessor to the current node, and
+  ///  in tandem add this node as a successor of the other node.
+  void addPredecessor(ExplodedNode* V, ExplodedGraph &G);
+
+  unsigned succ_size() const { return Succs.size(); }
+  unsigned pred_size() const { return Preds.size(); }
+  bool succ_empty() const { return Succs.empty(); }
+  bool pred_empty() const { return Preds.empty(); }
+
+  bool isSink() const { return Succs.getFlag(); }
+  void markAsSink() { Succs.setFlag(); }
+
+  ExplodedNode* getFirstPred() {
+    return pred_empty() ? NULL : *(pred_begin());
+  }
+
+  const ExplodedNode* getFirstPred() const {
+    return const_cast<ExplodedNode*>(this)->getFirstPred();
+  }
+
+  // Iterators over successor and predecessor vertices.
+  typedef ExplodedNode**       succ_iterator;
+  typedef const ExplodedNode* const * const_succ_iterator;
+  typedef ExplodedNode**       pred_iterator;
+  typedef const ExplodedNode* const * const_pred_iterator;
+
+  pred_iterator pred_begin() { return Preds.begin(); }
+  pred_iterator pred_end() { return Preds.end(); }
+
+  const_pred_iterator pred_begin() const {
+    return const_cast<ExplodedNode*>(this)->pred_begin();
+  }
+  const_pred_iterator pred_end() const {
+    return const_cast<ExplodedNode*>(this)->pred_end();
+  }
+
+  succ_iterator succ_begin() { return Succs.begin(); }
+  succ_iterator succ_end() { return Succs.end(); }
+
+  const_succ_iterator succ_begin() const {
+    return const_cast<ExplodedNode*>(this)->succ_begin();
+  }
+  const_succ_iterator succ_end() const {
+    return const_cast<ExplodedNode*>(this)->succ_end();
+  }
+
+  // For debugging.
+
+public:
+
+  class Auditor {
+  public:
+    virtual ~Auditor();
+    virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
+  };
+
+  static void SetAuditor(Auditor* A);
+};
+
+// FIXME: Is this class necessary?
+class InterExplodedGraphMap {
+  llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
+  friend class ExplodedGraph;
+
+public:
+  ExplodedNode* getMappedNode(const ExplodedNode* N) const;
+
+  InterExplodedGraphMap() {}
+  virtual ~InterExplodedGraphMap() {}
+};
+
+class ExplodedGraph {
+protected:
+  friend class CoreEngine;
+
+  // Type definitions.
+  typedef llvm::SmallVector<ExplodedNode*,2>    RootsTy;
+  typedef llvm::SmallVector<ExplodedNode*,10>   EndNodesTy;
+
+  /// Roots - The roots of the simulation graph. Usually there will be only
+  /// one, but clients are free to establish multiple subgraphs within a single
+  /// SimulGraph. Moreover, these subgraphs can often merge when paths from
+  /// different roots reach the same state at the same program location.
+  RootsTy Roots;
+
+  /// EndNodes - The nodes in the simulation graph which have been
+  ///  specially marked as the endpoint of an abstract simulation path.
+  EndNodesTy EndNodes;
+
+  /// Nodes - The nodes in the graph.
+  llvm::FoldingSet<ExplodedNode> Nodes;
+
+  /// BVC - Allocator and context for allocating nodes and their predecessor
+  /// and successor groups.
+  BumpVectorContext BVC;
+
+  /// NumNodes - The number of nodes in the graph.
+  unsigned NumNodes;
+
+public:
+  /// getNode - Retrieve the node associated with a (Location,State) pair,
+  ///  where the 'Location' is a ProgramPoint in the CFG.  If no node for
+  ///  this pair exists, it is created.  IsNew is set to true if
+  ///  the node was freshly created.
+
+  ExplodedNode* getNode(const ProgramPoint& L, const GRState *State,
+                        bool* IsNew = 0);
+
+  ExplodedGraph* MakeEmptyGraph() const {
+    return new ExplodedGraph();
+  }
+
+  /// addRoot - Add an untyped node to the set of roots.
+  ExplodedNode* addRoot(ExplodedNode* V) {
+    Roots.push_back(V);
+    return V;
+  }
+
+  /// addEndOfPath - Add an untyped node to the set of EOP nodes.
+  ExplodedNode* addEndOfPath(ExplodedNode* V) {
+    EndNodes.push_back(V);
+    return V;
+  }
+
+  ExplodedGraph() : NumNodes(0) {}
+
+  ~ExplodedGraph() {}
+
+  unsigned num_roots() const { return Roots.size(); }
+  unsigned num_eops() const { return EndNodes.size(); }
+
+  bool empty() const { return NumNodes == 0; }
+  unsigned size() const { return NumNodes; }
+
+  // Iterators.
+  typedef ExplodedNode                        NodeTy;
+  typedef llvm::FoldingSet<ExplodedNode>      AllNodesTy;
+  typedef NodeTy**                            roots_iterator;
+  typedef NodeTy* const *                     const_roots_iterator;
+  typedef NodeTy**                            eop_iterator;
+  typedef NodeTy* const *                     const_eop_iterator;
+  typedef AllNodesTy::iterator                node_iterator;
+  typedef AllNodesTy::const_iterator          const_node_iterator;
+
+  node_iterator nodes_begin() { return Nodes.begin(); }
+
+  node_iterator nodes_end() { return Nodes.end(); }
+
+  const_node_iterator nodes_begin() const { return Nodes.begin(); }
+
+  const_node_iterator nodes_end() const { return Nodes.end(); }
+
+  roots_iterator roots_begin() { return Roots.begin(); }
+
+  roots_iterator roots_end() { return Roots.end(); }
+
+  const_roots_iterator roots_begin() const { return Roots.begin(); }
+
+  const_roots_iterator roots_end() const { return Roots.end(); }
+
+  eop_iterator eop_begin() { return EndNodes.begin(); }
+
+  eop_iterator eop_end() { return EndNodes.end(); }
+
+  const_eop_iterator eop_begin() const { return EndNodes.begin(); }
+
+  const_eop_iterator eop_end() const { return EndNodes.end(); }
+
+  llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
+  BumpVectorContext &getNodeAllocator() { return BVC; }
+
+  typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
+
+  std::pair<ExplodedGraph*, InterExplodedGraphMap*>
+  Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
+       llvm::DenseMap<const void*, const void*> *InverseMap = 0) const;
+
+  ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg,
+                              const ExplodedNode* const * NEnd,
+                              InterExplodedGraphMap *M,
+                    llvm::DenseMap<const void*, const void*> *InverseMap) const;
+};
+
+class ExplodedNodeSet {
+  typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
+  ImplTy Impl;
+
+public:
+  ExplodedNodeSet(ExplodedNode* N) {
+    assert (N && !static_cast<ExplodedNode*>(N)->isSink());
+    Impl.insert(N);
+  }
+
+  ExplodedNodeSet() {}
+
+  inline void Add(ExplodedNode* N) {
+    if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
+  }
+
+  ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
+    Impl = X.Impl;
+    return *this;
+  }
+
+  typedef ImplTy::iterator       iterator;
+  typedef ImplTy::const_iterator const_iterator;
+
+  unsigned size() const { return Impl.size();  }
+  bool empty()    const { return Impl.empty(); }
+
+  void clear() { Impl.clear(); }
+  void insert(const ExplodedNodeSet &S) {
+    if (empty())
+      Impl = S.Impl;
+    else
+      Impl.insert(S.begin(), S.end());
+  }
+
+  inline iterator begin() { return Impl.begin(); }
+  inline iterator end()   { return Impl.end();   }
+
+  inline const_iterator begin() const { return Impl.begin(); }
+  inline const_iterator end()   const { return Impl.end();   }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+// GraphTraits
+
+namespace llvm {
+  template<> struct GraphTraits<clang::ento::ExplodedNode*> {
+    typedef clang::ento::ExplodedNode NodeType;
+    typedef NodeType::succ_iterator  ChildIteratorType;
+    typedef llvm::df_iterator<NodeType*>      nodes_iterator;
+
+    static inline NodeType* getEntryNode(NodeType* N) {
+      return N;
+    }
+
+    static inline ChildIteratorType child_begin(NodeType* N) {
+      return N->succ_begin();
+    }
+
+    static inline ChildIteratorType child_end(NodeType* N) {
+      return N->succ_end();
+    }
+
+    static inline nodes_iterator nodes_begin(NodeType* N) {
+      return df_begin(N);
+    }
+
+    static inline nodes_iterator nodes_end(NodeType* N) {
+      return df_end(N);
+    }
+  };
+
+  template<> struct GraphTraits<const clang::ento::ExplodedNode*> {
+    typedef const clang::ento::ExplodedNode NodeType;
+    typedef NodeType::const_succ_iterator   ChildIteratorType;
+    typedef llvm::df_iterator<NodeType*>       nodes_iterator;
+
+    static inline NodeType* getEntryNode(NodeType* N) {
+      return N;
+    }
+
+    static inline ChildIteratorType child_begin(NodeType* N) {
+      return N->succ_begin();
+    }
+
+    static inline ChildIteratorType child_end(NodeType* N) {
+      return N->succ_end();
+    }
+
+    static inline nodes_iterator nodes_begin(NodeType* N) {
+      return df_begin(N);
+    }
+
+    static inline nodes_iterator nodes_end(NodeType* N) {
+      return df_end(N);
+    }
+  };
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/PathSensitive/ExprEngine.h
new file mode 100644 (file)
index 0000000..407691a
--- /dev/null
@@ -0,0 +1,544 @@
+//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
+//  is built on CoreEngine, but provides the boilerplate to execute transfer
+//  functions and build the ExplodedGraph at the expression level.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_EXPRENGINE
+#define LLVM_CLANG_GR_EXPRENGINE
+
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtObjC.h"
+
+namespace clang {
+
+class ObjCForCollectionStmt;
+
+namespace ento {
+
+class AnalysisManager;
+class Checker;
+
+class ExprEngine : public SubEngine {
+  AnalysisManager &AMgr;
+
+  CoreEngine Engine;
+
+  /// G - the simulation graph.
+  ExplodedGraph& G;
+
+  /// Builder - The current StmtNodeBuilder which is used when building the
+  ///  nodes for a given statement.
+  StmtNodeBuilder* Builder;
+
+  /// StateMgr - Object that manages the data for all created states.
+  GRStateManager StateMgr;
+
+  /// SymMgr - Object that manages the symbol information.
+  SymbolManager& SymMgr;
+
+  /// svalBuilder - SValBuilder object that creates SVals from expressions.
+  SValBuilder &svalBuilder;
+
+  /// EntryNode - The immediate predecessor node.
+  ExplodedNode* EntryNode;
+
+  /// CleanedState - The state for EntryNode "cleaned" of all dead
+  ///  variables and symbols (as determined by a liveness analysis).
+  const GRState* CleanedState;
+
+  /// currentStmt - The current block-level statement.
+  const Stmt* currentStmt;
+
+  // Obj-C Class Identifiers.
+  IdentifierInfo* NSExceptionII;
+
+  // Obj-C Selectors.
+  Selector* NSExceptionInstanceRaiseSelectors;
+  Selector RaiseSel;
+
+  enum CallbackKind {
+    PreVisitStmtCallback,
+    PostVisitStmtCallback,
+    ProcessAssumeCallback,
+    EvalRegionChangesCallback
+  };
+
+  typedef uint32_t CallbackTag;
+
+  /// GetCallbackTag - Create a tag for a certain kind of callback. The 'Sub'
+  ///  argument can be used to differentiate callbacks that depend on another
+  ///  value from a small set of possibilities, such as statement classes.
+  static inline CallbackTag GetCallbackTag(CallbackKind K, uint32_t Sub = 0) {
+    assert(Sub == ((Sub << 8) >> 8) && "Tag sub-kind must fit into 24 bits");
+    return K | (Sub << 8);
+  }
+
+  typedef llvm::DenseMap<void *, unsigned> CheckerMap;
+  typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered;
+  typedef llvm::DenseMap<CallbackTag, CheckersOrdered *> CheckersOrderedCache;
+  
+  /// A registration map from checker tag to the index into the
+  ///  ordered checkers vector.
+  CheckerMap CheckerM;
+
+  /// An ordered vector of checkers that are called when evaluating
+  ///  various expressions and statements.
+  CheckersOrdered Checkers;
+
+  /// A map used for caching the checkers that respond to the callback for
+  ///  a particular callback tag.
+  CheckersOrderedCache COCache;
+
+  /// The BugReporter associated with this engine.  It is important that
+  ///  this object be placed at the very end of member variables so that its
+  ///  destructor is called before the rest of the ExprEngine is destroyed.
+  GRBugReporter BR;
+  
+  llvm::OwningPtr<TransferFuncs> TF;
+
+public:
+  ExprEngine(AnalysisManager &mgr, TransferFuncs *tf);
+
+  ~ExprEngine();
+
+  void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
+    Engine.ExecuteWorkList(L, Steps, 0);
+  }
+
+  /// Execute the work list with an initial state. Nodes that reaches the exit
+  /// of the function are added into the Dst set, which represent the exit
+  /// state of the function call.
+  void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+                                       const GRState *InitState, 
+                                       ExplodedNodeSet &Dst) {
+    Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
+  }
+
+  /// getContext - Return the ASTContext associated with this analysis.
+  ASTContext& getContext() const { return AMgr.getASTContext(); }
+
+  virtual AnalysisManager &getAnalysisManager() { return AMgr; }
+
+  SValBuilder &getSValBuilder() { return svalBuilder; }
+
+  TransferFuncs& getTF() { return *TF; }
+
+  BugReporter& getBugReporter() { return BR; }
+
+  StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
+
+  // FIXME: Remove once TransferFuncs is no longer referenced.
+  void setTransferFunction(TransferFuncs* tf);
+
+  /// ViewGraph - Visualize the ExplodedGraph created by executing the
+  ///  simulation.
+  void ViewGraph(bool trim = false);
+
+  void ViewGraph(ExplodedNode** Beg, ExplodedNode** End);
+
+  /// getInitialState - Return the initial state used for the root vertex
+  ///  in the ExplodedGraph.
+  const GRState* getInitialState(const LocationContext *InitLoc);
+
+  ExplodedGraph& getGraph() { return G; }
+  const ExplodedGraph& getGraph() const { return G; }
+
+  template <typename CHECKER>
+  void registerCheck(CHECKER *check) {
+    unsigned entry = Checkers.size();
+    void *tag = CHECKER::getTag();
+    Checkers.push_back(std::make_pair(tag, check));
+    CheckerM[tag] = entry;
+  }
+  
+  Checker *lookupChecker(void *tag) const;
+
+  template <typename CHECKER>
+  CHECKER *getChecker() const {
+     return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag()));
+  }
+
+  /// ProcessElement - Called by CoreEngine. Used to generate new successor
+  ///  nodes by processing the 'effects' of a CFG element.
+  void ProcessElement(const CFGElement E, StmtNodeBuilder& builder);
+
+  void ProcessStmt(const CFGStmt S, StmtNodeBuilder &builder);
+
+  void ProcessInitializer(const CFGInitializer I, StmtNodeBuilder &builder);
+
+  void ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &builder);
+
+  void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, 
+                            StmtNodeBuilder &builder);
+  void ProcessBaseDtor(const CFGBaseDtor D, StmtNodeBuilder &builder);
+  void ProcessMemberDtor(const CFGMemberDtor D, StmtNodeBuilder &builder);
+  void ProcessTemporaryDtor(const CFGTemporaryDtor D, 
+                            StmtNodeBuilder &builder);
+
+  /// ProcessBlockEntrance - Called by CoreEngine when start processing
+  ///  a CFGBlock.  This method returns true if the analysis should continue
+  ///  exploring the given path, and false otherwise.
+  bool ProcessBlockEntrance(const CFGBlock* B, const ExplodedNode *Pred,
+                            BlockCounter BC);
+
+  /// ProcessBranch - Called by CoreEngine.  Used to generate successor
+  ///  nodes by processing the 'effects' of a branch condition.
+  void ProcessBranch(const Stmt* Condition, const Stmt* Term, 
+                     BranchNodeBuilder& builder);
+
+  /// ProcessIndirectGoto - Called by CoreEngine.  Used to generate successor
+  ///  nodes by processing the 'effects' of a computed goto jump.
+  void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
+
+  /// ProcessSwitch - Called by CoreEngine.  Used to generate successor
+  ///  nodes by processing the 'effects' of a switch statement.
+  void ProcessSwitch(SwitchNodeBuilder& builder);
+
+  /// ProcessEndPath - Called by CoreEngine.  Used to generate end-of-path
+  ///  nodes when the control reaches the end of a function.
+  void ProcessEndPath(EndPathNodeBuilder& builder);
+
+  /// Generate the entry node of the callee.
+  void ProcessCallEnter(CallEnterNodeBuilder &builder);
+
+  /// Generate the first post callsite node.
+  void ProcessCallExit(CallExitNodeBuilder &builder);
+
+  /// Called by CoreEngine when the analysis worklist has terminated.
+  void ProcessEndWorklist(bool hasWorkRemaining);
+
+  /// evalAssume - Callback function invoked by the ConstraintManager when
+  ///  making assumptions about state values.
+  const GRState *ProcessAssume(const GRState *state, SVal cond,bool assumption);
+
+  /// WantsRegionChangeUpdate - Called by GRStateManager to determine if a
+  ///  region change should trigger a ProcessRegionChanges update.
+  bool WantsRegionChangeUpdate(const GRState* state);
+
+  /// ProcessRegionChanges - Called by GRStateManager whenever a change is made
+  ///  to the store. Used to update checkers that track region values.
+  const GRState* ProcessRegionChanges(const GRState *state,
+                                      const MemRegion * const *Begin,
+                                      const MemRegion * const *End);
+
+  virtual GRStateManager& getStateManager() { return StateMgr; }
+
+  StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
+
+  ConstraintManager& getConstraintManager() {
+    return StateMgr.getConstraintManager();
+  }
+
+  // FIXME: Remove when we migrate over to just using SValBuilder.
+  BasicValueFactory& getBasicVals() {
+    return StateMgr.getBasicVals();
+  }
+  const BasicValueFactory& getBasicVals() const {
+    return StateMgr.getBasicVals();
+  }
+
+  // FIXME: Remove when we migrate over to just using ValueManager.
+  SymbolManager& getSymbolManager() { return SymMgr; }
+  const SymbolManager& getSymbolManager() const { return SymMgr; }
+
+  // Functions for external checking of whether we have unfinished work
+  bool wasBlockAborted() const { return Engine.wasBlockAborted(); }
+  bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); }
+  bool hasWorkRemaining() const {
+    return wasBlockAborted() || Engine.getWorkList()->hasWork();
+  }
+
+  const CoreEngine &getCoreEngine() const { return Engine; }
+
+protected:
+  const GRState* GetState(ExplodedNode* N) {
+    return N == EntryNode ? CleanedState : N->getState();
+  }
+
+public:
+  ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S, 
+                         ExplodedNode* Pred, const GRState* St,
+                         ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+                         const void *tag = 0);
+
+  /// CheckerVisit - Dispatcher for performing checker-specific logic
+  ///  at specific statements.
+  void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
+                    CallbackKind Kind);
+
+  bool CheckerEvalCall(const CallExpr *CE, 
+                       ExplodedNodeSet &Dst, 
+                       ExplodedNode *Pred);
+
+  void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, 
+                              ExplodedNodeSet &Dst,
+                              const GRState *state,
+                              ExplodedNode *Pred);
+  
+  void CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
+                        ExplodedNodeSet &Src,  SVal location, SVal val,
+                        bool isPrevisit);
+
+  /// Visit - Transfer function logic for all statements.  Dispatches to
+  ///  other functions that handle specific kinds of statements.
+  void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+  /// VisitArraySubscriptExpr - Transfer function for array accesses.
+  void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* Ex,
+                                   ExplodedNode* Pred,
+                                   ExplodedNodeSet& Dst);
+
+  /// VisitAsmStmt - Transfer function logic for inline asm.
+  void VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+  void VisitAsmStmtHelperOutputs(const AsmStmt* A,
+                                 AsmStmt::const_outputs_iterator I,
+                                 AsmStmt::const_outputs_iterator E,
+                                 ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+  void VisitAsmStmtHelperInputs(const AsmStmt* A,
+                                AsmStmt::const_inputs_iterator I,
+                                AsmStmt::const_inputs_iterator E,
+                                ExplodedNode* Pred, ExplodedNodeSet& Dst);
+  
+  /// VisitBlockExpr - Transfer function logic for BlockExprs.
+  void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, 
+                      ExplodedNodeSet &Dst);
+
+  /// VisitBinaryOperator - Transfer function logic for binary operators.
+  void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode* Pred, 
+                           ExplodedNodeSet& Dst);
+
+
+  /// VisitCall - Transfer function for function calls.
+  void VisitCall(const CallExpr* CE, ExplodedNode* Pred,
+                 CallExpr::const_arg_iterator AI, 
+                 CallExpr::const_arg_iterator AE,
+                 ExplodedNodeSet& Dst);
+
+  /// VisitCast - Transfer function logic for all casts (implicit and explicit).
+  void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
+                ExplodedNodeSet &Dst);
+
+  /// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
+  void VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL, 
+                                ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+  /// Transfer function logic for DeclRefExprs and BlockDeclRefExprs.
+  void VisitCommonDeclRefExpr(const Expr* DR, const NamedDecl *D,
+                              ExplodedNode* Pred, ExplodedNodeSet& Dst);
+  
+  /// VisitDeclStmt - Transfer function logic for DeclStmts.
+  void VisitDeclStmt(const DeclStmt* DS, ExplodedNode* Pred, 
+                     ExplodedNodeSet& Dst);
+
+  /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
+  void VisitGuardedExpr(const Expr* Ex, const Expr* L, const Expr* R, 
+                        ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+  /// VisitCondInit - Transfer function for handling the initialization
+  ///  of a condition variable in an IfStmt, SwitchStmt, etc.
+  void VisitCondInit(const VarDecl *VD, const Stmt *S, ExplodedNode *Pred,
+                     ExplodedNodeSet& Dst);
+  
+  void VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
+                         ExplodedNodeSet& Dst);
+
+  /// VisitLogicalExpr - Transfer function logic for '&&', '||'
+  void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
+                        ExplodedNodeSet& Dst);
+
+  /// VisitMemberExpr - Transfer function for member expressions.
+  void VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, 
+                           ExplodedNodeSet& Dst);
+
+  /// Transfer function logic for ObjCAtSynchronizedStmts.
+  void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
+                                   ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+  /// Transfer function logic for computing the lvalue of an Objective-C ivar.
+  void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* DR, ExplodedNode* Pred,
+                                ExplodedNodeSet& Dst);
+
+  /// VisitObjCForCollectionStmt - Transfer function logic for
+  ///  ObjCForCollectionStmt.
+  void VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S, 
+                                  ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+  void VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S, 
+                                     ExplodedNode* Pred,
+                                     ExplodedNodeSet& Dst, SVal ElementV);
+
+  /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
+  void VisitObjCMessageExpr(const ObjCMessageExpr* ME, ExplodedNode* Pred, 
+                            ExplodedNodeSet& Dst);
+
+  /// VisitReturnStmt - Transfer function logic for return statements.
+  void VisitReturnStmt(const ReturnStmt* R, ExplodedNode* Pred, 
+                       ExplodedNodeSet& Dst);
+  
+  /// VisitOffsetOfExpr - Transfer function for offsetof.
+  void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred,
+                         ExplodedNodeSet& Dst);
+
+  /// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
+  void VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
+                              ExplodedNodeSet& Dst);
+
+  /// VisitUnaryOperator - Transfer function logic for unary operators.
+  void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred, 
+                          ExplodedNodeSet& Dst);
+
+  void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, 
+                        ExplodedNodeSet & Dst);
+
+  void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr,
+                                   ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+    VisitCXXConstructExpr(expr, 0, Pred, Dst);
+  }
+
+  void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest,
+                             ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+  void VisitCXXDestructor(const CXXDestructorDecl *DD,
+                          const MemRegion *Dest, const Stmt *S,
+                          ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+  void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred,
+                              ExplodedNodeSet &Dst);
+
+  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
+                                ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+  void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
+                       ExplodedNodeSet &Dst);
+
+  void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred,
+                          ExplodedNodeSet &Dst);
+
+  void VisitAggExpr(const Expr *E, const MemRegion *Dest, ExplodedNode *Pred,
+                    ExplodedNodeSet &Dst);
+
+  /// Create a C++ temporary object for an rvalue.
+  void CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, 
+                                ExplodedNodeSet &Dst);
+
+  /// Synthesize CXXThisRegion.
+  const CXXThisRegion *getCXXThisRegion(const CXXRecordDecl *RD,
+                                        const StackFrameContext *SFC);
+
+  const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *decl,
+                                        const StackFrameContext *frameCtx);
+
+  /// Evaluate arguments with a work list algorithm.
+  void evalArguments(ConstExprIterator AI, ConstExprIterator AE,
+                     const FunctionProtoType *FnType, 
+                     ExplodedNode *Pred, ExplodedNodeSet &Dst,
+                     bool FstArgAsLValue = false);
+
+  /// Evaluate method call itself. Used for CXXMethodCallExpr and
+  /// CXXOperatorCallExpr.
+  void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
+                      const Expr *ThisExpr, ExplodedNode *Pred,
+                      ExplodedNodeSet &Src, ExplodedNodeSet &Dst);
+
+  /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
+  ///  expressions of the form 'x != 0' and generate new nodes (stored in Dst)
+  ///  with those assumptions.
+  void evalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, 
+                         const Expr *Ex);
+
+  SVal evalMinus(SVal X) {
+    return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
+  }
+
+  SVal evalComplement(SVal X) {
+    return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X;
+  }
+
+public:
+
+  SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+                 NonLoc L, NonLoc R, QualType T) {
+    return svalBuilder.evalBinOpNN(state, op, L, R, T);
+  }
+
+  SVal evalBinOp(const GRState *state, BinaryOperator::Opcode op,
+                 NonLoc L, SVal R, QualType T) {
+    return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
+  }
+
+  SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+                 SVal LHS, SVal RHS, QualType T) {
+    return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
+  }
+  
+protected:
+  void evalObjCMessageExpr(ExplodedNodeSet& Dst, const ObjCMessageExpr* ME, 
+                           ExplodedNode* Pred, const GRState *state) {
+    assert (Builder && "StmtNodeBuilder must be defined.");
+    getTF().evalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state);
+  }
+
+  const GRState* MarkBranch(const GRState* St, const Stmt* Terminator,
+                            bool branchTaken);
+
+  /// evalBind - Handle the semantics of binding a value to a specific location.
+  ///  This method is used by evalStore, VisitDeclStmt, and others.
+  void evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, ExplodedNode* Pred,
+                const GRState* St, SVal location, SVal Val,
+                bool atDeclInit = false);
+
+public:
+  // FIXME: 'tag' should be removed, and a LocationContext should be used
+  // instead.
+  // FIXME: Comment on the meaning of the arguments, when 'St' may not
+  // be the same as Pred->state, and when 'location' may not be the
+  // same as state->getLValue(Ex).
+  /// Simulate a read of the result of Ex.
+  void evalLoad(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
+                const GRState* St, SVal location, const void *tag = 0,
+                QualType LoadTy = QualType());
+
+  // FIXME: 'tag' should be removed, and a LocationContext should be used
+  // instead.
+  void evalStore(ExplodedNodeSet& Dst, const Expr* AssignE, const Expr* StoreE,
+                 ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
+                 const void *tag = 0);
+private:
+  void evalLoadCommon(ExplodedNodeSet& Dst, const Expr* Ex, ExplodedNode* Pred,
+                      const GRState* St, SVal location, const void *tag,
+                      QualType LoadTy);
+
+  // FIXME: 'tag' should be removed, and a LocationContext should be used
+  // instead.
+  void evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred,
+                    const GRState* St, SVal location,
+                    const void *tag, bool isLoad);
+
+  bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h b/include/clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h
new file mode 100644 (file)
index 0000000..965ec3e
--- /dev/null
@@ -0,0 +1,81 @@
+//===-- ExprEngineBuilders.h - "Builder" classes for ExprEngine ---*- 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 smart builder "references" which are used to marshal
+//  builders between ExprEngine objects and their related components.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_EXPRENGINE_BUILDERS
+#define LLVM_CLANG_GR_EXPRENGINE_BUILDERS
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
+
+namespace clang {
+
+namespace ento {
+
+class StmtNodeBuilderRef {
+  ExplodedNodeSet &Dst;
+  StmtNodeBuilder &B;
+  ExprEngine& Eng;
+  ExplodedNode* Pred;
+  const GRState* state;
+  const Stmt* stmt;
+  const unsigned OldSize;
+  const bool AutoCreateNode;
+  SaveAndRestore<bool> OldSink;
+  SaveAndRestore<const void*> OldTag;
+  SaveOr OldHasGen;
+
+private:
+  friend class ExprEngine;
+
+  StmtNodeBuilderRef(); // do not implement
+  void operator=(const StmtNodeBuilderRef&); // do not implement
+
+  StmtNodeBuilderRef(ExplodedNodeSet &dst,
+                       StmtNodeBuilder &builder,
+                       ExprEngine& eng,
+                       ExplodedNode* pred,
+                       const GRState *st,
+                       const Stmt* s, bool auto_create_node)
+  : Dst(dst), B(builder), Eng(eng), Pred(pred),
+    state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
+    OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {}
+
+public:
+
+  ~StmtNodeBuilderRef() {
+    // Handle the case where no nodes where generated.  Auto-generate that
+    // contains the updated state if we aren't generating sinks.
+    if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) {
+      if (AutoCreateNode)
+        B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+      else
+        Dst.Add(Pred);
+    }
+  }
+
+  const GRState *getState() { return state; }
+
+  GRStateManager& getStateManager() {
+    return Eng.getStateManager();
+  }
+
+  ExplodedNode* MakeNode(const GRState* state) {
+    return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+  }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/PathSensitive/GRState.h
new file mode 100644 (file)
index 0000000..dcdb6e2
--- /dev/null
@@ -0,0 +1,760 @@
+//== GRState.h - Path-sensitive "State" for tracking 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 SymbolRef, ExprBindKey, and GRState*.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_VALUESTATE_H
+#define LLVM_CLANG_GR_VALUESTATE_H
+
+#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/Environment.h"
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Casting.h"
+
+namespace llvm {
+class APSInt;
+class BumpPtrAllocator;
+class raw_ostream;
+}
+
+namespace clang {
+class ASTContext;
+
+namespace ento {
+
+class GRStateManager;
+class Checker;
+
+typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
+                                                       SubEngine&);
+typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
+
+//===----------------------------------------------------------------------===//
+// GRStateTrait - Traits used by the Generic Data Map of a GRState.
+//===----------------------------------------------------------------------===//
+
+template <typename T> struct GRStatePartialTrait;
+
+template <typename T> struct GRStateTrait {
+  typedef typename T::data_type data_type;
+  static inline void* GDMIndex() { return &T::TagInt; }
+  static inline void* MakeVoidPtr(data_type D) { return (void*) D; }
+  static inline data_type MakeData(void* const* P) {
+    return P ? (data_type) *P : (data_type) 0;
+  }
+};
+
+class GRStateManager;
+
+/// GRState - This class encapsulates:
+///
+///    1. A mapping from expressions to values (Environment)
+///    2. A mapping from locations to values (Store)
+///    3. Constraints on symbolic values (GenericDataMap)
+///
+///  Together these represent the "abstract state" of a program.
+///
+///  GRState is intended to be used as a functional object; that is,
+///  once it is created and made "persistent" in a FoldingSet, its
+///  values will never change.
+class GRState : public llvm::FoldingSetNode {
+public:
+  typedef llvm::ImmutableSet<llvm::APSInt*>                IntSetTy;
+  typedef llvm::ImmutableMap<void*, void*>                 GenericDataMap;
+
+private:
+  void operator=(const GRState& R) const; // Do not implement.
+
+  friend class GRStateManager;
+
+  GRStateManager *StateMgr;
+  Environment Env;           // Maps a Stmt to its current SVal.
+  Store St;                  // Maps a location to its current value.
+  GenericDataMap   GDM;      // Custom data stored by a client of this class.
+
+  /// makeWithStore - Return a GRState with the same values as the current
+  ///  state with the exception of using the specified Store.
+  const GRState *makeWithStore(Store store) const;
+
+public:
+
+  /// This ctor is used when creating the first GRState object.
+  GRState(GRStateManager *mgr, const Environment& env,
+          Store st, GenericDataMap gdm)
+    : StateMgr(mgr),
+      Env(env),
+      St(st),
+      GDM(gdm) {}
+
+  /// Copy ctor - We must explicitly define this or else the "Next" ptr
+  ///  in FoldingSetNode will also get copied.
+  GRState(const GRState& RHS)
+    : llvm::FoldingSetNode(),
+      StateMgr(RHS.StateMgr),
+      Env(RHS.Env),
+      St(RHS.St),
+      GDM(RHS.GDM) {}
+
+  /// getStateManager - Return the GRStateManager associated with this state.
+  GRStateManager &getStateManager() const {
+    return *StateMgr;
+  }
+
+  /// getEnvironment - Return the environment associated with this state.
+  ///  The environment is the mapping from expressions to values.
+  const Environment& getEnvironment() const { return Env; }
+
+  /// getStore - Return the store associated with this state.  The store
+  ///  is a mapping from locations to values.
+  Store getStore() const { return St; }
+
+  void setStore(Store s) { St = s; }
+
+  /// getGDM - Return the generic data map associated with this state.
+  GenericDataMap getGDM() const { return GDM; }
+
+  void setGDM(GenericDataMap gdm) { GDM = gdm; }
+
+  /// Profile - Profile the contents of a GRState object for use in a
+  ///  FoldingSet.  Two GRState objects are considered equal if they
+  ///  have the same Environment, Store, and GenericDataMap.
+  static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
+    V->Env.Profile(ID);
+    ID.AddPointer(V->St);
+    V->GDM.Profile(ID);
+  }
+
+  /// Profile - Used to profile the contents of this object for inclusion
+  ///  in a FoldingSet.
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    Profile(ID, this);
+  }
+
+  BasicValueFactory &getBasicVals() const;
+  SymbolManager &getSymbolManager() const;
+
+  //==---------------------------------------------------------------------==//
+  // Constraints on values.
+  //==---------------------------------------------------------------------==//
+  //
+  // Each GRState records constraints on symbolic values.  These constraints
+  // are managed using the ConstraintManager associated with a GRStateManager.
+  // As constraints gradually accrue on symbolic values, added constraints
+  // may conflict and indicate that a state is infeasible (as no real values
+  // could satisfy all the constraints).  This is the principal mechanism
+  // for modeling path-sensitivity in ExprEngine/GRState.
+  //
+  // Various "assume" methods form the interface for adding constraints to
+  // symbolic values.  A call to 'assume' indicates an assumption being placed
+  // on one or symbolic values.  'assume' methods take the following inputs:
+  //
+  //  (1) A GRState object representing the current state.
+  //
+  //  (2) The assumed constraint (which is specific to a given "assume" method).
+  //
+  //  (3) A binary value "Assumption" that indicates whether the constraint is
+  //      assumed to be true or false.
+  //
+  // The output of "assume*" is a new GRState object with the added constraints.
+  // If no new state is feasible, NULL is returned.
+  //
+
+  const GRState *assume(DefinedOrUnknownSVal cond, bool assumption) const;
+
+  /// This method assumes both "true" and "false" for 'cond', and
+  ///  returns both corresponding states.  It's shorthand for doing
+  ///  'assume' twice.
+  std::pair<const GRState*, const GRState*>
+  assume(DefinedOrUnknownSVal cond) const;
+
+  const GRState *assumeInBound(DefinedOrUnknownSVal idx,
+                               DefinedOrUnknownSVal upperBound,
+                               bool assumption) const;
+
+  //==---------------------------------------------------------------------==//
+  // Utility methods for getting regions.
+  //==---------------------------------------------------------------------==//
+
+  const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
+
+  //==---------------------------------------------------------------------==//
+  // Binding and retrieving values to/from the environment and symbolic store.
+  //==---------------------------------------------------------------------==//
+
+  /// BindCompoundLiteral - Return the state that has the bindings currently
+  ///  in this state plus the bindings for the CompoundLiteral.
+  const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL,
+                                     const LocationContext *LC,
+                                     SVal V) const;
+
+  /// Create a new state by binding the value 'V' to the statement 'S' in the
+  /// state's environment.
+  const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
+
+  /// Create a new state by binding the value 'V' and location 'locaton' to the
+  /// statement 'S' in the state's environment.
+  const GRState *bindExprAndLocation(const Stmt *S, SVal location, SVal V)
+    const;
+  
+  const GRState *bindDecl(const VarRegion *VR, SVal V) const;
+
+  const GRState *bindDeclWithNoInit(const VarRegion *VR) const;
+
+  const GRState *bindLoc(Loc location, SVal V) const;
+
+  const GRState *bindLoc(SVal location, SVal V) const;
+
+  const GRState *bindDefault(SVal loc, SVal V) const;
+
+  const GRState *unbindLoc(Loc LV) const;
+
+  /// InvalidateRegion - Returns the state with bindings for the given region
+  ///  cleared from the store. See InvalidateRegions.
+  const GRState *InvalidateRegion(const MemRegion *R,
+                                  const Expr *E, unsigned BlockCount,
+                                  StoreManager::InvalidatedSymbols *IS = NULL)
+                                  const {
+    return InvalidateRegions(&R, &R+1, E, BlockCount, IS, false);
+  }
+
+  /// InvalidateRegions - Returns the state with bindings for the given regions
+  ///  cleared from the store. The regions are provided as a continuous array
+  ///  from Begin to End. Optionally invalidates global regions as well.
+  const GRState *InvalidateRegions(const MemRegion * const *Begin,
+                                   const MemRegion * const *End,
+                                   const Expr *E, unsigned BlockCount,
+                                   StoreManager::InvalidatedSymbols *IS,
+                                   bool invalidateGlobals) const;
+
+  /// EnterStackFrame - Returns the state for entry to the given stack frame,
+  ///  preserving the current state.
+  const GRState *EnterStackFrame(const StackFrameContext *frame) const;
+
+  /// Get the lvalue for a variable reference.
+  Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
+
+  /// Get the lvalue for a StringLiteral.
+  Loc getLValue(const StringLiteral *literal) const;
+
+  Loc getLValue(const CompoundLiteralExpr *literal, 
+                const LocationContext *LC) const;
+
+  /// Get the lvalue for an ivar reference.
+  SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
+
+  /// Get the lvalue for a field reference.
+  SVal getLValue(const FieldDecl *decl, SVal Base) const;
+
+  /// Get the lvalue for an array index.
+  SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
+
+  const llvm::APSInt *getSymVal(SymbolRef sym) const;
+
+  /// Returns the SVal bound to the statement 'S' in the state's environment.
+  SVal getSVal(const Stmt* S) const;
+  
+  SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
+
+  SVal getSVal(Loc LV, QualType T = QualType()) const;
+
+  /// Returns the "raw" SVal bound to LV before any value simplfication.
+  SVal getRawSVal(Loc LV, QualType T= QualType()) const;
+
+  SVal getSVal(const MemRegion* R) const;
+
+  SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+  
+  const llvm::APSInt *getSymVal(SymbolRef sym);
+
+  bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
+  
+  bool scanReachableSymbols(const SVal *I, const SVal *E,
+                            SymbolVisitor &visitor) const;
+  
+  bool scanReachableSymbols(const MemRegion * const *I, 
+                            const MemRegion * const *E,
+                            SymbolVisitor &visitor) const;
+
+  template <typename CB> CB scanReachableSymbols(SVal val) const;
+  template <typename CB> CB scanReachableSymbols(const SVal *beg,
+                                                 const SVal *end) const;
+  
+  template <typename CB> CB
+  scanReachableSymbols(const MemRegion * const *beg,
+                       const MemRegion * const *end) const;
+
+  //==---------------------------------------------------------------------==//
+  // Accessing the Generic Data Map (GDM).
+  //==---------------------------------------------------------------------==//
+
+  void* const* FindGDM(void* K) const;
+
+  template<typename T>
+  const GRState *add(typename GRStateTrait<T>::key_type K) const;
+
+  template <typename T>
+  typename GRStateTrait<T>::data_type
+  get() const {
+    return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
+  }
+
+  template<typename T>
+  typename GRStateTrait<T>::lookup_type
+  get(typename GRStateTrait<T>::key_type key) const {
+    void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
+    return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
+  }
+
+  template <typename T>
+  typename GRStateTrait<T>::context_type get_context() const;
+
+
+  template<typename T>
+  const GRState *remove(typename GRStateTrait<T>::key_type K) const;
+
+  template<typename T>
+  const GRState *remove(typename GRStateTrait<T>::key_type K,
+                        typename GRStateTrait<T>::context_type C) const;
+  template <typename T>
+  const GRState *remove() const;
+
+  template<typename T>
+  const GRState *set(typename GRStateTrait<T>::data_type D) const;
+
+  template<typename T>
+  const GRState *set(typename GRStateTrait<T>::key_type K,
+                     typename GRStateTrait<T>::value_type E) const;
+
+  template<typename T>
+  const GRState *set(typename GRStateTrait<T>::key_type K,
+                     typename GRStateTrait<T>::value_type E,
+                     typename GRStateTrait<T>::context_type C) const;
+
+  template<typename T>
+  bool contains(typename GRStateTrait<T>::key_type key) const {
+    void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
+    return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
+  }
+
+  // State pretty-printing.
+  class Printer {
+  public:
+    virtual ~Printer() {}
+    virtual void Print(llvm::raw_ostream& Out, const GRState* state,
+                       const char* nl, const char* sep) = 0;
+  };
+
+  // Pretty-printing.
+  void print(llvm::raw_ostream& Out, CFG &C, const char *nl = "\n",
+             const char *sep = "") const;
+
+  void printStdErr(CFG &C) const;
+
+  void printDOT(llvm::raw_ostream& Out, CFG &C) const;
+};
+
+class GRStateSet {
+  typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
+  ImplTy Impl;
+public:
+  GRStateSet() {}
+
+  inline void Add(const GRState* St) {
+    Impl.insert(St);
+  }
+
+  typedef ImplTy::const_iterator iterator;
+
+  inline unsigned size() const { return Impl.size();  }
+  inline bool empty()    const { return Impl.empty(); }
+
+  inline iterator begin() const { return Impl.begin(); }
+  inline iterator end() const { return Impl.end();   }
+
+  class AutoPopulate {
+    GRStateSet& S;
+    unsigned StartSize;
+    const GRState* St;
+  public:
+    AutoPopulate(GRStateSet& s, const GRState* st)
+      : S(s), StartSize(S.size()), St(st) {}
+
+    ~AutoPopulate() {
+      if (StartSize == S.size())
+        S.Add(St);
+    }
+  };
+};
+
+//===----------------------------------------------------------------------===//
+// GRStateManager - Factory object for GRStates.
+//===----------------------------------------------------------------------===//
+
+class GRStateManager {
+  friend class GRState;
+  friend class ExprEngine; // FIXME: Remove.
+private:
+  /// Eng - The SubEngine that owns this state manager.
+  SubEngine &Eng;
+
+  EnvironmentManager                   EnvMgr;
+  llvm::OwningPtr<StoreManager>        StoreMgr;
+  llvm::OwningPtr<ConstraintManager>   ConstraintMgr;
+
+  GRState::GenericDataMap::Factory     GDMFactory;
+
+  typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
+  GDMContextsTy GDMContexts;
+
+  /// Printers - A set of printer objects used for pretty-printing a GRState.
+  ///  GRStateManager owns these objects.
+  std::vector<GRState::Printer*> Printers;
+
+  /// StateSet - FoldingSet containing all the states created for analyzing
+  ///  a particular function.  This is used to unique states.
+  llvm::FoldingSet<GRState> StateSet;
+
+  /// Object that manages the data for all created SVals.
+  llvm::OwningPtr<SValBuilder> svalBuilder;
+
+  /// Alloc - A BumpPtrAllocator to allocate states.
+  llvm::BumpPtrAllocator &Alloc;
+
+public:
+  GRStateManager(ASTContext& Ctx,
+                 StoreManagerCreator CreateStoreManager,
+                 ConstraintManagerCreator CreateConstraintManager,
+                 llvm::BumpPtrAllocator& alloc,
+                 SubEngine &subeng)
+    : Eng(subeng),
+      EnvMgr(alloc),
+      GDMFactory(alloc),
+      svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
+      Alloc(alloc) {
+    StoreMgr.reset((*CreateStoreManager)(*this));
+    ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
+  }
+
+  ~GRStateManager();
+
+  const GRState *getInitialState(const LocationContext *InitLoc);
+
+  ASTContext &getContext() { return svalBuilder->getContext(); }
+  const ASTContext &getContext() const { return svalBuilder->getContext(); }
+
+  BasicValueFactory &getBasicVals() {
+    return svalBuilder->getBasicValueFactory();
+  }
+  const BasicValueFactory& getBasicVals() const {
+    return svalBuilder->getBasicValueFactory();
+  }
+
+  SValBuilder &getSValBuilder() {
+    return *svalBuilder;
+  }
+
+  SymbolManager &getSymbolManager() {
+    return svalBuilder->getSymbolManager();
+  }
+  const SymbolManager &getSymbolManager() const {
+    return svalBuilder->getSymbolManager();
+  }
+
+  llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
+
+  MemRegionManager& getRegionManager() {
+    return svalBuilder->getRegionManager();
+  }
+  const MemRegionManager& getRegionManager() const {
+    return svalBuilder->getRegionManager();
+  }
+
+  StoreManager& getStoreManager() { return *StoreMgr; }
+  ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
+  SubEngine& getOwningEngine() { return Eng; }
+
+  const GRState* RemoveDeadBindings(const GRState* St,
+                                    const StackFrameContext *LCtx,
+                                    SymbolReaper& SymReaper);
+
+  /// Marshal a new state for the callee in another translation unit.
+  /// 'state' is owned by the caller's engine.
+  const GRState *MarshalState(const GRState *state, const StackFrameContext *L);
+
+public:
+
+  SVal ArrayToPointer(Loc Array) {
+    return StoreMgr->ArrayToPointer(Array);
+  }
+
+  // Methods that manipulate the GDM.
+  const GRState* addGDM(const GRState* St, void* Key, void* Data);
+  const GRState *removeGDM(const GRState *state, void *Key);
+
+  // Methods that query & manipulate the Store.
+
+  void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
+    StoreMgr->iterBindings(state->getStore(), F);
+  }
+
+  const GRState* getPersistentState(GRState& Impl);
+
+  //==---------------------------------------------------------------------==//
+  // Generic Data Map methods.
+  //==---------------------------------------------------------------------==//
+  //
+  // GRStateManager and GRState support a "generic data map" that allows
+  // different clients of GRState objects to embed arbitrary data within a
+  // GRState object.  The generic data map is essentially an immutable map
+  // from a "tag" (that acts as the "key" for a client) and opaque values.
+  // Tags/keys and values are simply void* values.  The typical way that clients
+  // generate unique tags are by taking the address of a static variable.
+  // Clients are responsible for ensuring that data values referred to by a
+  // the data pointer are immutable (and thus are essentially purely functional
+  // data).
+  //
+  // The templated methods below use the GRStateTrait<T> class
+  // to resolve keys into the GDM and to return data values to clients.
+  //
+
+  // Trait based GDM dispatch.
+  template <typename T>
+  const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
+    return addGDM(st, GRStateTrait<T>::GDMIndex(),
+                  GRStateTrait<T>::MakeVoidPtr(D));
+  }
+
+  template<typename T>
+  const GRState* set(const GRState* st,
+                     typename GRStateTrait<T>::key_type K,
+                     typename GRStateTrait<T>::value_type V,
+                     typename GRStateTrait<T>::context_type C) {
+
+    return addGDM(st, GRStateTrait<T>::GDMIndex(),
+     GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
+  }
+
+  template <typename T>
+  const GRState* add(const GRState* st,
+                     typename GRStateTrait<T>::key_type K,
+                     typename GRStateTrait<T>::context_type C) {
+    return addGDM(st, GRStateTrait<T>::GDMIndex(),
+        GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
+  }
+
+  template <typename T>
+  const GRState* remove(const GRState* st,
+                        typename GRStateTrait<T>::key_type K,
+                        typename GRStateTrait<T>::context_type C) {
+
+    return addGDM(st, GRStateTrait<T>::GDMIndex(),
+     GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
+  }
+
+  template <typename T>
+  const GRState *remove(const GRState *st) {
+    return removeGDM(st, GRStateTrait<T>::GDMIndex());
+  }
+
+  void* FindGDMContext(void* index,
+                       void* (*CreateContext)(llvm::BumpPtrAllocator&),
+                       void  (*DeleteContext)(void*));
+
+  template <typename T>
+  typename GRStateTrait<T>::context_type get_context() {
+    void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
+                             GRStateTrait<T>::CreateContext,
+                             GRStateTrait<T>::DeleteContext);
+
+    return GRStateTrait<T>::MakeContext(p);
+  }
+
+  const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
+    return ConstraintMgr->getSymVal(St, sym);
+  }
+
+  void EndPath(const GRState* St) {
+    ConstraintMgr->EndPath(St);
+  }
+};
+
+
+//===----------------------------------------------------------------------===//
+// Out-of-line method definitions for GRState.
+//===----------------------------------------------------------------------===//
+
+inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
+  return getStateManager().getSymVal(this, sym);
+}
+  
+inline const VarRegion* GRState::getRegion(const VarDecl *D,
+                                           const LocationContext *LC) const {
+  return getStateManager().getRegionManager().getVarRegion(D, LC);
+}
+
+inline const GRState *GRState::assume(DefinedOrUnknownSVal Cond,
+                                      bool Assumption) const {
+  if (Cond.isUnknown())
+    return this;
+  
+  return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond),
+                                                 Assumption);
+}
+  
+inline std::pair<const GRState*, const GRState*>
+GRState::assume(DefinedOrUnknownSVal Cond) const {
+  if (Cond.isUnknown())
+    return std::make_pair(this, this);
+  
+  return getStateManager().ConstraintMgr->assumeDual(this,
+                                                     cast<DefinedSVal>(Cond));
+}
+
+inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
+  return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
+}
+
+inline Loc GRState::getLValue(const VarDecl* VD,
+                               const LocationContext *LC) const {
+  return getStateManager().StoreMgr->getLValueVar(VD, LC);
+}
+
+inline Loc GRState::getLValue(const StringLiteral *literal) const {
+  return getStateManager().StoreMgr->getLValueString(literal);
+}
+
+inline Loc GRState::getLValue(const CompoundLiteralExpr *literal,
+                               const LocationContext *LC) const {
+  return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
+}
+
+inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
+  return getStateManager().StoreMgr->getLValueIvar(D, Base);
+}
+
+inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const {
+  return getStateManager().StoreMgr->getLValueField(D, Base);
+}
+
+inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
+  if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
+    return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
+  return UnknownVal();
+}
+
+inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
+  return getStateManager().getSymVal(this, sym);
+}
+
+inline SVal GRState::getSVal(const Stmt* Ex) const {
+  return Env.getSVal(Ex, *getStateManager().svalBuilder);
+}
+
+inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
+  if (const Expr *Ex = dyn_cast<Expr>(S)) {
+    QualType T = Ex->getType();
+    if (Loc::IsLocType(T) || T->isIntegerType())
+      return getSVal(S);
+  }
+
+  return UnknownVal();
+}
+
+inline SVal GRState::getRawSVal(Loc LV, QualType T) const {
+  return getStateManager().StoreMgr->Retrieve(St, LV, T);
+}
+
+inline SVal GRState::getSVal(const MemRegion* R) const {
+  return getStateManager().StoreMgr->Retrieve(St, loc::MemRegionVal(R));
+}
+
+inline BasicValueFactory &GRState::getBasicVals() const {
+  return getStateManager().getBasicVals();
+}
+
+inline SymbolManager &GRState::getSymbolManager() const {
+  return getStateManager().getSymbolManager();
+}
+
+template<typename T>
+const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
+  return getStateManager().add<T>(this, K, get_context<T>());
+}
+
+template <typename T>
+typename GRStateTrait<T>::context_type GRState::get_context() const {
+  return getStateManager().get_context<T>();
+}
+
+template<typename T>
+const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
+  return getStateManager().remove<T>(this, K, get_context<T>());
+}
+
+template<typename T>
+const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
+                               typename GRStateTrait<T>::context_type C) const {
+  return getStateManager().remove<T>(this, K, C);
+}
+
+template <typename T>
+const GRState *GRState::remove() const {
+  return getStateManager().remove<T>(this);
+}
+
+template<typename T>
+const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
+  return getStateManager().set<T>(this, D);
+}
+
+template<typename T>
+const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
+                            typename GRStateTrait<T>::value_type E) const {
+  return getStateManager().set<T>(this, K, E, get_context<T>());
+}
+
+template<typename T>
+const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
+                            typename GRStateTrait<T>::value_type E,
+                            typename GRStateTrait<T>::context_type C) const {
+  return getStateManager().set<T>(this, K, E, C);
+}
+
+template <typename CB>
+CB GRState::scanReachableSymbols(SVal val) const {
+  CB cb(this);
+  scanReachableSymbols(val, cb);
+  return cb;
+}
+  
+template <typename CB>
+CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
+  CB cb(this);
+  scanReachableSymbols(beg, end, cb);
+  return cb;
+}
+
+template <typename CB>
+CB GRState::scanReachableSymbols(const MemRegion * const *beg,
+                                 const MemRegion * const *end) const {
+  CB cb(this);
+  scanReachableSymbols(beg, end, cb);
+  return cb;
+}
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/PathSensitive/GRStateTrait.h
new file mode 100644 (file)
index 0000000..914625a
--- /dev/null
@@ -0,0 +1,152 @@
+//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- 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 partial implementations of template specializations of
+//  the class GRStateTrait<>.  GRStateTrait<> is used by GRState to implement
+//  set/get methods for mapulating a GRState's generic data map.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LLVM_CLANG_GR_GRSTATETRAIT_H
+#define LLVM_CLANG_GR_GRSTATETRAIT_H
+
+namespace llvm {
+  class BumpPtrAllocator;
+  template <typename K, typename D, typename I> class ImmutableMap;
+  template <typename K, typename I> class ImmutableSet;
+  template <typename T> class ImmutableList;
+  template <typename T> class ImmutableListImpl;
+}
+
+namespace clang {
+
+namespace ento {
+  template <typename T> struct GRStatePartialTrait;
+
+  // Partial-specialization for ImmutableMap.
+
+  template <typename Key, typename Data, typename Info>
+  struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
+    typedef llvm::ImmutableMap<Key,Data,Info> data_type;
+    typedef typename data_type::Factory&      context_type;
+    typedef Key                               key_type;
+    typedef Data                              value_type;
+    typedef const value_type*                 lookup_type;
+
+    static inline data_type MakeData(void* const* p) {
+      return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
+    }
+    static inline void* MakeVoidPtr(data_type B) {
+      return B.getRoot();
+    }
+    static lookup_type Lookup(data_type B, key_type K) {
+      return B.lookup(K);
+    }
+    static data_type Set(data_type B, key_type K, value_type E,context_type F){
+      return F.add(B, K, E);
+    }
+
+    static data_type Remove(data_type B, key_type K, context_type F) {
+      return F.remove(B, K);
+    }
+
+    static inline context_type MakeContext(void* p) {
+      return *((typename data_type::Factory*) p);
+    }
+
+    static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+      return new typename data_type::Factory(Alloc);
+    }
+
+    static void DeleteContext(void* Ctx) {
+      delete (typename data_type::Factory*) Ctx;
+    }
+  };
+
+
+  // Partial-specialization for ImmutableSet.
+
+  template <typename Key, typename Info>
+  struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
+    typedef llvm::ImmutableSet<Key,Info>      data_type;
+    typedef typename data_type::Factory&      context_type;
+    typedef Key                               key_type;
+
+    static inline data_type MakeData(void* const* p) {
+      return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
+    }
+
+    static inline void* MakeVoidPtr(data_type B) {
+      return B.getRoot();
+    }
+
+    static data_type Add(data_type B, key_type K, context_type F) {
+      return F.add(B, K);
+    }
+
+    static data_type Remove(data_type B, key_type K, context_type F) {
+      return F.remove(B, K);
+    }
+
+    static bool Contains(data_type B, key_type K) {
+      return B.contains(K);
+    }
+
+    static inline context_type MakeContext(void* p) {
+      return *((typename data_type::Factory*) p);
+    }
+
+    static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+      return new typename data_type::Factory(Alloc);
+    }
+
+    static void DeleteContext(void* Ctx) {
+      delete (typename data_type::Factory*) Ctx;
+    }
+  };
+
+  // Partial-specialization for ImmutableList.
+
+  template <typename T>
+  struct GRStatePartialTrait< llvm::ImmutableList<T> > {
+    typedef llvm::ImmutableList<T>            data_type;
+    typedef T                                 key_type;
+    typedef typename data_type::Factory&      context_type;
+
+    static data_type Add(data_type L, key_type K, context_type F) {
+      return F.add(K, L);
+    }
+
+    static inline data_type MakeData(void* const* p) {
+      return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
+               : data_type(0);
+    }
+
+    static inline void* MakeVoidPtr(data_type D) {
+      return  (void*) D.getInternalPointer();
+    }
+
+    static inline context_type MakeContext(void* p) {
+      return *((typename data_type::Factory*) p);
+    }
+
+    static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+      return new typename data_type::Factory(Alloc);
+    }
+
+    static void DeleteContext(void* Ctx) {
+      delete (typename data_type::Factory*) Ctx;
+    }
+  };
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/PathSensitive/MemRegion.h
new file mode 100644 (file)
index 0000000..33779a9
--- /dev/null
@@ -0,0 +1,1077 @@
+//== MemRegion.h - Abstract memory regions for static analysis --*- 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 MemRegion and its subclasses.  MemRegion defines a
+//  partially-typed abstraction of memory useful for path-sensitive dataflow
+//  analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_MEMREGION_H
+#define LLVM_CLANG_GR_MEMREGION_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/FoldingSet.h"
+#include <string>
+
+namespace llvm {
+class BumpPtrAllocator;
+class raw_ostream;
+}
+
+namespace clang {
+
+class LocationContext;
+class StackFrameContext;
+
+namespace ento {
+
+class MemRegionManager;
+class MemSpaceRegion;
+class SValBuilder;
+class VarRegion;
+class CodeTextRegion;
+
+/// Represent a region's offset within the top level base region.
+class RegionOffset {
+  /// The base region.
+  const MemRegion *R;
+
+  /// The bit offset within the base region. It shouldn't be negative.
+  int64_t Offset;
+
+public:
+  RegionOffset(const MemRegion *r) : R(r), Offset(0) {}
+  RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {}
+
+  const MemRegion *getRegion() const { return R; }
+  int64_t getOffset() const { return Offset; }
+};
+
+//===----------------------------------------------------------------------===//
+// Base region classes.
+//===----------------------------------------------------------------------===//
+
+/// MemRegion - The root abstract class for all memory regions.
+class MemRegion : public llvm::FoldingSetNode {
+  friend class MemRegionManager;
+public:
+  enum Kind {
+    // Memory spaces.
+    GenericMemSpaceRegionKind,
+    StackLocalsSpaceRegionKind,
+    StackArgumentsSpaceRegionKind,
+    HeapSpaceRegionKind,
+    UnknownSpaceRegionKind,
+    NonStaticGlobalSpaceRegionKind,
+    StaticGlobalSpaceRegionKind,
+    BEG_GLOBAL_MEMSPACES = NonStaticGlobalSpaceRegionKind,
+    END_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
+    BEG_MEMSPACES = GenericMemSpaceRegionKind,
+    END_MEMSPACES = StaticGlobalSpaceRegionKind,
+    // Untyped regions.
+    SymbolicRegionKind,
+    AllocaRegionKind,
+    // Typed regions.
+    BEG_TYPED_REGIONS,
+    FunctionTextRegionKind = BEG_TYPED_REGIONS,
+    BlockTextRegionKind,
+    BlockDataRegionKind,
+    CompoundLiteralRegionKind,
+    CXXThisRegionKind,
+    StringRegionKind,
+    ElementRegionKind,
+    // Decl Regions.
+    BEG_DECL_REGIONS,
+    VarRegionKind = BEG_DECL_REGIONS,
+    FieldRegionKind,
+    ObjCIvarRegionKind,
+    END_DECL_REGIONS = ObjCIvarRegionKind,
+    CXXTempObjectRegionKind,
+    CXXBaseObjectRegionKind,
+    END_TYPED_REGIONS = CXXBaseObjectRegionKind
+  };
+    
+private:
+  const Kind kind;
+
+protected:
+  MemRegion(Kind k) : kind(k) {}
+  virtual ~MemRegion();
+
+public:
+  ASTContext &getContext() const;
+
+  virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
+
+  virtual MemRegionManager* getMemRegionManager() const = 0;
+
+  std::string getString() const;
+
+  const MemSpaceRegion *getMemorySpace() const;
+
+  const MemRegion *getBaseRegion() const;
+
+  const MemRegion *StripCasts() const;
+
+  bool hasGlobalsOrParametersStorage() const;
+
+  bool hasStackStorage() const;
+  
+  bool hasStackNonParametersStorage() const;
+  
+  bool hasStackParametersStorage() const;
+
+  /// Compute the offset within the top level memory object.
+  RegionOffset getAsOffset() const;
+
+  virtual void dumpToStream(llvm::raw_ostream& os) const;
+
+  void dump() const;
+
+  Kind getKind() const { return kind; }
+
+  template<typename RegionTy> const RegionTy* getAs() const;
+
+  virtual bool isBoundable() const { return false; }
+
+  static bool classof(const MemRegion*) { return true; }
+};
+
+/// MemSpaceRegion - A memory region that represents and "memory space";
+///  for example, the set of global variables, the stack frame, etc.
+class MemSpaceRegion : public MemRegion {
+protected:
+  friend class MemRegionManager;
+  
+  MemRegionManager *Mgr;
+
+  MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind)
+    : MemRegion(k), Mgr(mgr) {
+    assert(classof(this));
+  }
+
+  MemRegionManager* getMemRegionManager() const { return Mgr; }
+
+public:
+  bool isBoundable() const { return false; }
+  
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+
+  static bool classof(const MemRegion *R) {
+    Kind k = R->getKind();
+    return k >= BEG_MEMSPACES && k <= END_MEMSPACES;
+  }
+};
+  
+class GlobalsSpaceRegion : public MemSpaceRegion {
+protected:
+  GlobalsSpaceRegion(MemRegionManager *mgr, Kind k)
+    : MemSpaceRegion(mgr, k) {}
+public:
+  static bool classof(const MemRegion *R) {
+    Kind k = R->getKind();
+    return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
+  }
+};
+  
+class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
+  friend class MemRegionManager;
+
+  const CodeTextRegion *CR;
+  
+  StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr)
+    : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {}
+
+public:
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+  
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  const CodeTextRegion *getCodeRegion() const { return CR; }
+
+  static bool classof(const MemRegion *R) {
+    return R->getKind() == StaticGlobalSpaceRegionKind;
+  }
+};
+  
+class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
+  friend class MemRegionManager;
+  
+  NonStaticGlobalSpaceRegion(MemRegionManager *mgr)
+    : GlobalsSpaceRegion(mgr, NonStaticGlobalSpaceRegionKind) {}
+  
+public:
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  static bool classof(const MemRegion *R) {
+    return R->getKind() == NonStaticGlobalSpaceRegionKind;
+  }
+};
+  
+class HeapSpaceRegion : public MemSpaceRegion {
+  friend class MemRegionManager;
+  
+  HeapSpaceRegion(MemRegionManager *mgr)
+    : MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
+public:
+  static bool classof(const MemRegion *R) {
+    return R->getKind() == HeapSpaceRegionKind;
+  }
+};
+  
+class UnknownSpaceRegion : public MemSpaceRegion {
+  friend class MemRegionManager;
+  UnknownSpaceRegion(MemRegionManager *mgr)
+    : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+public:
+  static bool classof(const MemRegion *R) {
+    return R->getKind() == UnknownSpaceRegionKind;
+  }
+};
+  
+class StackSpaceRegion : public MemSpaceRegion {
+private:
+  const StackFrameContext *SFC;
+
+protected:
+  StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
+    : MemSpaceRegion(mgr, k), SFC(sfc) {
+    assert(classof(this));
+  }
+
+public:  
+  const StackFrameContext *getStackFrame() const { return SFC; }
+  
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+
+  static bool classof(const MemRegion *R) {
+    Kind k = R->getKind();
+    return k >= StackLocalsSpaceRegionKind &&
+           k <= StackArgumentsSpaceRegionKind;
+  }  
+};
+  
+class StackLocalsSpaceRegion : public StackSpaceRegion {
+private:
+  friend class MemRegionManager;
+  StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
+    : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
+public:
+  static bool classof(const MemRegion *R) {
+    return R->getKind() == StackLocalsSpaceRegionKind;
+  }
+};
+
+class StackArgumentsSpaceRegion : public StackSpaceRegion {
+private:
+  friend class MemRegionManager;
+  StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
+    : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
+public:
+  static bool classof(const MemRegion *R) {
+    return R->getKind() == StackArgumentsSpaceRegionKind;
+  }
+};
+
+
+/// SubRegion - A region that subsets another larger region.  Most regions
+///  are subclasses of SubRegion.
+class SubRegion : public MemRegion {
+protected:
+  const MemRegion* superRegion;
+  SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
+public:
+  const MemRegion* getSuperRegion() const {
+    return superRegion;
+  }
+
+  /// getExtent - Returns the size of the region in bytes.
+  virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const {
+    return UnknownVal();
+  }
+
+  MemRegionManager* getMemRegionManager() const;
+
+  bool isSubRegionOf(const MemRegion* R) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() > END_MEMSPACES;
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// MemRegion subclasses.
+//===----------------------------------------------------------------------===//
+
+/// AllocaRegion - A region that represents an untyped blob of bytes created
+///  by a call to 'alloca'.
+class AllocaRegion : public SubRegion {
+  friend class MemRegionManager;
+protected:
+  unsigned Cnt; // Block counter.  Used to distinguish different pieces of
+                // memory allocated by alloca at the same call site.
+  const Expr* Ex;
+
+  AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion)
+    : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
+
+public:
+
+  const Expr* getExpr() const { return Ex; }
+
+  bool isBoundable() const { return true; }
+
+  DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
+
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
+                            unsigned Cnt, const MemRegion *superRegion);
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == AllocaRegionKind;
+  }
+};
+
+/// TypedRegion - An abstract class representing regions that are typed.
+class TypedRegion : public SubRegion {
+protected:
+  TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
+
+public:
+  virtual QualType getValueType() const = 0;
+
+  virtual QualType getLocationType() const {
+    // FIXME: We can possibly optimize this later to cache this value.
+    return getContext().getPointerType(getValueType());
+  }
+
+  QualType getDesugaredValueType(ASTContext &Context) const {
+    QualType T = getValueType();
+    return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
+  }
+
+  QualType getDesugaredLocationType(ASTContext &Context) const {
+    return getLocationType().getDesugaredType(Context);
+  }
+
+  bool isBoundable() const { return true; }
+
+  static bool classof(const MemRegion* R) {
+    unsigned k = R->getKind();
+    return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+  }
+};
+
+
+class CodeTextRegion : public TypedRegion {
+protected:
+  CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
+public:
+  QualType getValueType() const {
+    assert(0 && "Do not get the object type of a CodeTextRegion.");
+    return QualType();
+  }
+  
+  bool isBoundable() const { return false; }
+    
+  static bool classof(const MemRegion* R) {
+    Kind k = R->getKind();
+    return k >= FunctionTextRegionKind && k <= BlockTextRegionKind;
+  }
+};
+
+/// FunctionTextRegion - A region that represents code texts of function.
+class FunctionTextRegion : public CodeTextRegion {
+  const FunctionDecl *FD;
+public:
+  FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg)
+    : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {}
+  
+  QualType getLocationType() const {
+    return getContext().getPointerType(FD->getType());
+  }
+  
+  const FunctionDecl *getDecl() const {
+    return FD;
+  }
+    
+  virtual void dumpToStream(llvm::raw_ostream& os) const;
+  
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+  
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD,
+                            const MemRegion*);
+  
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == FunctionTextRegionKind;
+  }
+};
+  
+  
+/// BlockTextRegion - A region that represents code texts of blocks (closures).
+///  Blocks are represented with two kinds of regions.  BlockTextRegions
+///  represent the "code", while BlockDataRegions represent instances of blocks,
+///  which correspond to "code+data".  The distinction is important, because
+///  like a closure a block captures the values of externally referenced
+///  variables.
+class BlockTextRegion : public CodeTextRegion {
+  friend class MemRegionManager;
+
+  const BlockDecl *BD;
+  AnalysisContext *AC;
+  CanQualType locTy;
+
+  BlockTextRegion(const BlockDecl *bd, CanQualType lTy,
+                  AnalysisContext *ac, const MemRegion* sreg)
+    : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {}
+
+public:
+  QualType getLocationType() const {
+    return locTy;
+  }
+  
+  const BlockDecl *getDecl() const {
+    return BD;
+  }
+
+  AnalysisContext *getAnalysisContext() const { return AC; }
+    
+  virtual void dumpToStream(llvm::raw_ostream& os) const;
+  
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+  
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
+                            CanQualType, const AnalysisContext*,
+                            const MemRegion*);
+  
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == BlockTextRegionKind;
+  }
+};
+  
+/// BlockDataRegion - A region that represents a block instance.
+///  Blocks are represented with two kinds of regions.  BlockTextRegions
+///  represent the "code", while BlockDataRegions represent instances of blocks,
+///  which correspond to "code+data".  The distinction is important, because
+///  like a closure a block captures the values of externally referenced
+///  variables.
+class BlockDataRegion : public SubRegion {
+  friend class MemRegionManager;
+  const BlockTextRegion *BC;
+  const LocationContext *LC; // Can be null */
+  void *ReferencedVars;
+
+  BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
+                  const MemRegion *sreg)
+  : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {}
+
+public:  
+  const BlockTextRegion *getCodeRegion() const { return BC; }
+  
+  const BlockDecl *getDecl() const { return BC->getDecl(); }
+  
+  class referenced_vars_iterator {
+    const MemRegion * const *R;
+  public:
+    explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {}
+    
+    operator const MemRegion * const *() const {
+      return R;
+    }
+    
+    const VarRegion* operator*() const {
+      return cast<VarRegion>(*R);
+    }
+    
+    bool operator==(const referenced_vars_iterator &I) const {
+      return I.R == R;
+    }
+    bool operator!=(const referenced_vars_iterator &I) const {
+      return I.R != R;
+    }
+    referenced_vars_iterator& operator++() {
+      ++R;
+      return *this;
+    }
+  };
+      
+  referenced_vars_iterator referenced_vars_begin() const;
+  referenced_vars_iterator referenced_vars_end() const;  
+    
+  virtual void dumpToStream(llvm::raw_ostream& os) const;
+    
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+    
+  static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *,
+                            const LocationContext *, const MemRegion *);
+    
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == BlockDataRegionKind;
+  }
+private:
+  void LazyInitializeReferencedVars();
+};
+
+/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
+///  clases, SymbolicRegion represents a region that serves as an alias for
+///  either a real region, a NULL pointer, etc.  It essentially is used to
+///  map the concept of symbolic values into the domain of regions.  Symbolic
+///  regions do not need to be typed.
+class SymbolicRegion : public SubRegion {
+protected:
+  const SymbolRef sym;
+
+public:
+  SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
+    : SubRegion(sreg, SymbolicRegionKind), sym(s) {}
+
+  SymbolRef getSymbol() const {
+    return sym;
+  }
+
+  bool isBoundable() const { return true; }
+
+  DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
+
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+                            SymbolRef sym,
+                            const MemRegion* superRegion);
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == SymbolicRegionKind;
+  }
+};
+
+/// StringRegion - Region associated with a StringLiteral.
+class StringRegion : public TypedRegion {
+  friend class MemRegionManager;
+  const StringLiteral* Str;
+protected:
+
+  StringRegion(const StringLiteral* str, const MemRegion* sreg)
+    : TypedRegion(sreg, StringRegionKind), Str(str) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+                            const StringLiteral* Str,
+                            const MemRegion* superRegion);
+
+public:
+
+  const StringLiteral* getStringLiteral() const { return Str; }
+
+  QualType getValueType() const {
+    return Str->getType();
+  }
+
+  DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
+
+  bool isBoundable() const { return false; }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    ProfileRegion(ID, Str, superRegion);
+  }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == StringRegionKind;
+  }
+};
+
+/// CompoundLiteralRegion - A memory region representing a compound literal.
+///   Compound literals are essentially temporaries that are stack allocated
+///   or in the global constant pool.
+class CompoundLiteralRegion : public TypedRegion {
+private:
+  friend class MemRegionManager;
+  const CompoundLiteralExpr* CL;
+
+  CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
+    : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+                            const CompoundLiteralExpr* CL,
+                            const MemRegion* superRegion);
+public:
+  QualType getValueType() const {
+    return CL->getType();
+  }
+
+  bool isBoundable() const { return !CL->isFileScope(); }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == CompoundLiteralRegionKind;
+  }
+};
+
+class DeclRegion : public TypedRegion {
+protected:
+  const Decl* D;
+
+  DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
+    : TypedRegion(sReg, k), D(d) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+                      const MemRegion* superRegion, Kind k);
+
+public:
+  const Decl* getDecl() const { return D; }
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+
+  DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
+
+  static bool classof(const MemRegion* R) {
+    unsigned k = R->getKind();
+    return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS;
+  }
+};
+
+class VarRegion : public DeclRegion {
+  friend class MemRegionManager;
+
+  // Constructors and private methods.
+  VarRegion(const VarDecl* vd, const MemRegion* sReg)
+    : DeclRegion(vd, sReg, VarRegionKind) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
+                            const MemRegion *superRegion) {
+    DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+  }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+
+public:
+  const VarDecl *getDecl() const { return cast<VarDecl>(D); }
+
+  const StackFrameContext *getStackFrame() const;
+  
+  QualType getValueType() const {
+    // FIXME: We can cache this if needed.
+    return getDecl()->getType();
+  }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == VarRegionKind;
+  }
+};
+  
+/// CXXThisRegion - Represents the region for the implicit 'this' parameter
+///  in a call to a C++ method.  This region doesn't represent the object
+///  referred to by 'this', but rather 'this' itself.
+class CXXThisRegion : public TypedRegion {
+  friend class MemRegionManager;
+  CXXThisRegion(const PointerType *thisPointerTy,
+                const MemRegion *sReg)
+    : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+                            const PointerType *PT,
+                            const MemRegion *sReg);
+
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+
+public:  
+  QualType getValueType() const {
+    return QualType(ThisPointerTy, 0);
+  }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+  
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == CXXThisRegionKind;
+  }
+
+private:
+  const PointerType *ThisPointerTy;
+};
+
+class FieldRegion : public DeclRegion {
+  friend class MemRegionManager;
+
+  FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
+    : DeclRegion(fd, sReg, FieldRegionKind) {}
+
+public:
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
+
+  QualType getValueType() const {
+    // FIXME: We can cache this if needed.
+    return getDecl()->getType();
+  }
+
+  DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const;
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD,
+                            const MemRegion* superRegion) {
+    DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+  }
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == FieldRegionKind;
+  }
+};
+
+class ObjCIvarRegion : public DeclRegion {
+
+  friend class MemRegionManager;
+
+  ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
+    : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd,
+                            const MemRegion* superRegion) {
+    DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
+  }
+
+public:
+  const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); }
+  QualType getValueType() const { return getDecl()->getType(); }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == ObjCIvarRegionKind;
+  }
+};
+//===----------------------------------------------------------------------===//
+// Auxillary data classes for use with MemRegions.
+//===----------------------------------------------------------------------===//
+
+class ElementRegion;
+
+class RegionRawOffset {
+private:
+  friend class ElementRegion;
+
+  const MemRegion *Region;
+  int64_t Offset;
+
+  RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
+    : Region(reg), Offset(offset) {}
+
+public:
+  // FIXME: Eventually support symbolic offsets.
+  int64_t getByteOffset() const { return Offset; }
+  const MemRegion *getRegion() const { return Region; }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+  void dump() const;
+};
+
+class ElementRegion : public TypedRegion {
+  friend class MemRegionManager;
+
+  QualType ElementType;
+  NonLoc Index;
+
+  ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
+    : TypedRegion(sReg, ElementRegionKind),
+      ElementType(elementType), Index(Idx) {
+    assert((!isa<nonloc::ConcreteInt>(&Idx) ||
+           cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
+           "The index must be signed");
+  }
+
+  static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
+                            SVal Idx, const MemRegion* superRegion);
+
+public:
+
+  NonLoc getIndex() const { return Index; }
+
+  QualType getValueType() const {
+    return ElementType;
+  }
+
+  QualType getElementType() const {
+    return ElementType;
+  }
+  /// Compute the offset within the array. The array might also be a subobject.
+  RegionRawOffset getAsArrayOffset() const;
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  void Profile(llvm::FoldingSetNodeID& ID) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == ElementRegionKind;
+  }
+};
+
+// C++ temporary object associated with an expression.
+class CXXTempObjectRegion : public TypedRegion {
+  friend class MemRegionManager;
+
+  Expr const *Ex;
+
+  CXXTempObjectRegion(Expr const *E, MemRegion const *sReg) 
+    : TypedRegion(sReg, CXXTempObjectRegionKind), Ex(E) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+                            Expr const *E, const MemRegion *sReg);
+  
+public:
+  QualType getValueType() const {
+    return Ex->getType();
+  }
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+
+  static bool classof(const MemRegion* R) {
+    return R->getKind() == CXXTempObjectRegionKind;
+  }
+};
+
+// CXXBaseObjectRegion represents a base object within a C++ object. It is 
+// identified by the base class declaration and the region of its parent object.
+class CXXBaseObjectRegion : public TypedRegion {
+  friend class MemRegionManager;
+
+  const CXXRecordDecl *decl;
+
+  CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg)
+    : TypedRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
+
+  static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+                            const CXXRecordDecl *decl, const MemRegion *sReg);
+
+public:
+  QualType getValueType() const;
+
+  void dumpToStream(llvm::raw_ostream& os) const;
+
+  void Profile(llvm::FoldingSetNodeID &ID) const;
+
+  static bool classof(const MemRegion *region) {
+    return region->getKind() == CXXBaseObjectRegionKind;
+  }
+};
+
+template<typename RegionTy>
+const RegionTy* MemRegion::getAs() const {
+  if (const RegionTy* RT = dyn_cast<RegionTy>(this))
+    return RT;
+
+  return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager - Factory object for creating regions.
+//===----------------------------------------------------------------------===//
+
+class MemRegionManager {
+  ASTContext &C;
+  llvm::BumpPtrAllocator& A;
+  llvm::FoldingSet<MemRegion> Regions;
+
+  NonStaticGlobalSpaceRegion *globals;
+  
+  llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> 
+    StackLocalsSpaceRegions;
+  llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *>
+    StackArgumentsSpaceRegions;
+  llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *>
+    StaticsGlobalSpaceRegions;
+
+  HeapSpaceRegion *heap;
+  UnknownSpaceRegion *unknown;
+  MemSpaceRegion *code;
+
+public:
+  MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
+    : C(c), A(a), globals(0), heap(0), unknown(0), code(0) {}
+
+  ~MemRegionManager();
+
+  ASTContext &getContext() { return C; }
+  
+  llvm::BumpPtrAllocator &getAllocator() { return A; }
+
+  /// getStackLocalsRegion - Retrieve the memory region associated with the
+  ///  specified stack frame.
+  const StackLocalsSpaceRegion *
+  getStackLocalsRegion(const StackFrameContext *STC);
+
+  /// getStackArgumentsRegion - Retrieve the memory region associated with
+  ///  function/method arguments of the specified stack frame.
+  const StackArgumentsSpaceRegion *
+  getStackArgumentsRegion(const StackFrameContext *STC);
+
+  /// getGlobalsRegion - Retrieve the memory region associated with
+  ///  global variables.
+  const GlobalsSpaceRegion *getGlobalsRegion(const CodeTextRegion *R = 0);
+
+  /// getHeapRegion - Retrieve the memory region associated with the
+  ///  generic "heap".
+  const HeapSpaceRegion *getHeapRegion();
+
+  /// getUnknownRegion - Retrieve the memory region associated with unknown
+  /// memory space.
+  const MemSpaceRegion *getUnknownRegion();
+
+  const MemSpaceRegion *getCodeRegion();
+
+  /// getAllocaRegion - Retrieve a region associated with a call to alloca().
+  const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt,
+                                      const LocationContext *LC);
+
+  /// getCompoundLiteralRegion - Retrieve the region associated with a
+  ///  given CompoundLiteral.
+  const CompoundLiteralRegion*
+  getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+                           const LocationContext *LC);
+  
+  /// getCXXThisRegion - Retrieve the [artifical] region associated with the
+  ///  parameter 'this'.
+  const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
+                                        const LocationContext *LC);
+
+  /// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+  const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
+
+  const StringRegion* getStringRegion(const StringLiteral* Str);
+
+  /// getVarRegion - Retrieve or create the memory region associated with
+  ///  a specified VarDecl and LocationContext.
+  const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
+
+  /// getVarRegion - Retrieve or create the memory region associated with
+  ///  a specified VarDecl and super region.
+  const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR);
+  
+  /// getElementRegion - Retrieve the memory region associated with the
+  ///  associated element type, index, and super region.
+  const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx,
+                                        const MemRegion *superRegion,
+                                        ASTContext &Ctx);
+
+  const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
+                                                 const MemRegion *superRegion) {
+    return getElementRegion(ER->getElementType(), ER->getIndex(),
+                            superRegion, ER->getContext());
+  }
+
+  /// getFieldRegion - Retrieve or create the memory region associated with
+  ///  a specified FieldDecl.  'superRegion' corresponds to the containing
+  ///  memory region (which typically represents the memory representing
+  ///  a structure or class).
+  const FieldRegion *getFieldRegion(const FieldDecl* fd,
+                                    const MemRegion* superRegion);
+
+  const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
+                                             const MemRegion *superRegion) {
+    return getFieldRegion(FR->getDecl(), superRegion);
+  }
+
+  /// getObjCIvarRegion - Retrieve or create the memory region associated with
+  ///   a specified Objective-c instance variable.  'superRegion' corresponds
+  ///   to the containing region (which typically represents the Objective-C
+  ///   object).
+  const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
+                                          const MemRegion* superRegion);
+
+  const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
+                                                    LocationContext const *LC);
+
+  const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl,
+                                                  const MemRegion *superRegion);
+
+  const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
+  const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
+                                            CanQualType locTy,
+                                            AnalysisContext *AC);
+  
+  /// getBlockDataRegion - Get the memory region associated with an instance
+  ///  of a block.  Unlike many other MemRegions, the LocationContext*
+  ///  argument is allowed to be NULL for cases where we have no known
+  ///  context.
+  const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
+                                            const LocationContext *lc = NULL);
+
+  bool isGlobalsRegion(const MemRegion* R) {
+    assert(R);
+    return R == globals;
+  }
+  
+private:
+  template <typename RegionTy, typename A1>
+  RegionTy* getRegion(const A1 a1);
+
+  template <typename RegionTy, typename A1>
+  RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion);
+
+  template <typename RegionTy, typename A1, typename A2>
+  RegionTy* getRegion(const A1 a1, const A2 a2);
+
+  template <typename RegionTy, typename A1, typename A2>
+  RegionTy* getSubRegion(const A1 a1, const A2 a2,
+                         const MemRegion* superRegion);
+
+  template <typename RegionTy, typename A1, typename A2, typename A3>
+  RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3,
+                         const MemRegion* superRegion);
+  
+  template <typename REG>
+  const REG* LazyAllocate(REG*& region);
+  
+  template <typename REG, typename ARG>
+  const REG* LazyAllocate(REG*& region, ARG a);
+};
+
+//===----------------------------------------------------------------------===//
+// Out-of-line member definitions.
+//===----------------------------------------------------------------------===//
+
+inline ASTContext& MemRegion::getContext() const {
+  return getMemRegionManager()->getContext();
+}
+  
+} // end GR namespace
+
+} // end clang namespace
+
+//===----------------------------------------------------------------------===//
+// Pretty-printing regions.
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+static inline raw_ostream& operator<<(raw_ostream& os,
+                                      const clang::ento::MemRegion* R) {
+  R->dumpToStream(os);
+  return os;
+}
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/PathSensitive/SValBuilder.h
new file mode 100644 (file)
index 0000000..0705510
--- /dev/null
@@ -0,0 +1,259 @@
+// SValBuilder.h - Construction of SVals from evaluating expressions -*- 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 SValBuilder, a class that defines the interface for
+//  "symbolical evaluators" which construct an SVal from an expression.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_SVALBUILDER
+#define LLVM_CLANG_GR_SVALBUILDER
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+
+namespace clang {
+
+namespace ento {
+
+class GRState;
+
+class SValBuilder {
+protected:
+  ASTContext &Context;
+  
+  /// Manager of APSInt values.
+  BasicValueFactory BasicVals;
+
+  /// Manages the creation of symbols.
+  SymbolManager SymMgr;
+
+  /// Manages the creation of memory regions.
+  MemRegionManager MemMgr;
+
+  GRStateManager &StateMgr;
+
+  /// The scalar type to use for array indices.
+  const QualType ArrayIndexTy;
+  
+  /// The width of the scalar type used for array indices.
+  const unsigned ArrayIndexWidth;
+
+public:
+  // FIXME: Make these protected again one RegionStoreManager correctly
+  // handles loads from differening bound value types.
+  virtual SVal evalCastNL(NonLoc val, QualType castTy) = 0;
+  virtual SVal evalCastL(Loc val, QualType castTy) = 0;
+
+public:
+  SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+              GRStateManager &stateMgr)
+    : Context(context), BasicVals(context, alloc),
+      SymMgr(context, BasicVals, alloc),
+      MemMgr(context, alloc),
+      StateMgr(stateMgr),
+      ArrayIndexTy(context.IntTy),
+      ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
+
+  virtual ~SValBuilder() {}
+
+  SVal evalCast(SVal V, QualType castTy, QualType originalType);
+  
+  virtual SVal evalMinus(NonLoc val) = 0;
+
+  virtual SVal evalComplement(NonLoc val) = 0;
+
+  virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode Op,
+                           NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
+
+  virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode Op,
+                           Loc lhs, Loc rhs, QualType resultTy) = 0;
+
+  virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode Op,
+                           Loc lhs, NonLoc rhs, QualType resultTy) = 0;
+
+  /// getKnownValue - evaluates a given SVal. If the SVal has only one possible
+  ///  (integer) value, that value is returned. Otherwise, returns NULL.
+  virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V) = 0;
+  
+  SVal evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+                 SVal L, SVal R, QualType T);
+  
+  DefinedOrUnknownSVal evalEQ(const GRState *ST, DefinedOrUnknownSVal L,
+                              DefinedOrUnknownSVal R);
+
+  ASTContext &getContext() { return Context; }
+  const ASTContext &getContext() const { return Context; }
+
+  GRStateManager &getStateManager() { return StateMgr; }
+  
+  QualType getConditionType() const {
+    return  getContext().IntTy;
+  }
+  
+  QualType getArrayIndexType() const {
+    return ArrayIndexTy;
+  }
+
+  BasicValueFactory &getBasicValueFactory() { return BasicVals; }
+  const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
+
+  SymbolManager &getSymbolManager() { return SymMgr; }
+  const SymbolManager &getSymbolManager() const { return SymMgr; }
+
+  MemRegionManager &getRegionManager() { return MemMgr; }
+  const MemRegionManager &getRegionManager() const { return MemMgr; }
+
+  // Forwarding methods to SymbolManager.
+
+  const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+                                          unsigned VisitCount,
+                                          const void* SymbolTag = 0) {
+    return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag);
+  }
+
+  const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
+                                          const void* SymbolTag = 0) {
+    return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
+  }
+
+  /// makeZeroVal - Construct an SVal representing '0' for the specified type.
+  DefinedOrUnknownSVal makeZeroVal(QualType T);
+
+  /// getRegionValueSymbolVal - make a unique symbol for value of R.
+  DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedRegion *R);
+
+  DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
+                                            const Expr *E, unsigned Count);
+  DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
+                                            const Expr *E, QualType T,
+                                            unsigned Count);
+
+  DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
+                                                      const TypedRegion *R);
+
+  DefinedSVal getMetadataSymbolVal(const void *SymbolTag, const MemRegion *MR,
+                                   const Expr *E, QualType T, unsigned Count);
+
+  DefinedSVal getFunctionPointer(const FunctionDecl *FD);
+  
+  DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy,
+                              const LocationContext *LC);
+
+  NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
+    return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
+  }
+
+  NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) {
+    return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R));
+  }
+
+  NonLoc makeZeroArrayIndex() {
+    return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
+  }
+
+  NonLoc makeArrayIndex(uint64_t idx) {
+    return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
+  }
+
+  SVal convertToArrayIndex(SVal V);
+
+  nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) {
+    return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
+                                        I->getType()->isUnsignedIntegerType()));
+  }
+
+  nonloc::ConcreteInt makeIntVal(const CXXBoolLiteralExpr *E) {
+    return E->getValue() ? nonloc::ConcreteInt(BasicVals.getValue(1, 1, true))
+                         : nonloc::ConcreteInt(BasicVals.getValue(0, 1, true));
+  }
+
+  nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
+    return nonloc::ConcreteInt(BasicVals.getValue(V));
+  }
+
+  loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) {
+    return loc::ConcreteInt(BasicVals.getValue(v));
+  }
+
+  NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) {
+    return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
+  }
+
+  DefinedSVal makeIntVal(uint64_t X, QualType T) {
+    if (Loc::IsLocType(T))
+      return loc::ConcreteInt(BasicVals.getValue(X, T));
+
+    return nonloc::ConcreteInt(BasicVals.getValue(X, T));
+  }
+
+  NonLoc makeIntVal(uint64_t X, bool isUnsigned) {
+    return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
+  }
+
+  NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) {
+    return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned));
+  }
+
+  NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) {
+    return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
+  }
+
+  NonLoc makeLocAsInteger(Loc V, unsigned Bits) {
+    return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits));
+  }
+
+  NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+                    const llvm::APSInt& rhs, QualType T);
+
+  NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+                    const SymExpr *rhs, QualType T);
+
+  NonLoc makeTruthVal(bool b, QualType T) {
+    return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
+  }
+
+  NonLoc makeTruthVal(bool b) {
+    return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
+  }
+
+  Loc makeNull() {
+    return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
+  }
+
+  Loc makeLoc(SymbolRef Sym) {
+    return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym));
+  }
+
+  Loc makeLoc(const MemRegion* R) {
+    return loc::MemRegionVal(R);
+  }
+
+  Loc makeLoc(const AddrLabelExpr* E) {
+    return loc::GotoLabel(E->getLabel());
+  }
+
+  Loc makeLoc(const llvm::APSInt& V) {
+    return loc::ConcreteInt(BasicVals.getValue(V));
+  }
+
+};
+
+SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
+                                     ASTContext &context,
+                                     GRStateManager &stateMgr);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/PathSensitive/SVals.h
new file mode 100644 (file)
index 0000000..d4d8469
--- /dev/null
@@ -0,0 +1,522 @@
+//== SVals.h - Abstract Values for Static Analysis ---------*- 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 SVal, Loc, and NonLoc, classes that represent
+//  abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_RVALUE_H
+#define LLVM_CLANG_GR_RVALUE_H
+
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/ImmutableList.h"
+
+namespace llvm {
+  class raw_ostream;
+}
+
+//==------------------------------------------------------------------------==//
+//  Base SVal types.
+//==------------------------------------------------------------------------==//
+
+namespace clang {
+
+namespace ento {
+
+class CompoundValData;
+class LazyCompoundValData;
+class GRState;
+class BasicValueFactory;
+class MemRegion;
+class TypedRegion;
+class MemRegionManager;
+class GRStateManager;
+class SValBuilder;
+
+/// SVal - This represents a symbolic expression, which can be either
+///  an L-value or an R-value.
+///
+class SVal {
+public:
+  enum BaseKind {
+    // The enumerators must be representable using 2 bits.
+    UndefinedKind = 0,  // for subclass UndefinedVal (an uninitialized value)
+    UnknownKind = 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)
+  };
+  enum { BaseBits = 2, BaseMask = 0x3 };
+
+protected:
+  const void* Data;
+
+  /// The lowest 2 bits are a BaseKind (0 -- 3).
+  ///  The higher bits are an unsigned "kind" value.
+  unsigned Kind;
+
+protected:
+  explicit SVal(const void* d, bool isLoc, unsigned ValKind)
+  : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
+
+  explicit SVal(BaseKind k, const void* D = NULL)
+    : Data(D), Kind(k) {}
+
+public:
+  explicit SVal() : Data(0), Kind(0) {}
+  ~SVal() {}
+
+  /// BufferTy - A temporary buffer to hold a set of SVals.
+  typedef llvm::SmallVector<SVal,5> BufferTy;
+
+  inline unsigned getRawKind() const { return Kind; }
+  inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
+  inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
+
+  inline void Profile(llvm::FoldingSetNodeID& ID) const {
+    ID.AddInteger((unsigned) getRawKind());
+    ID.AddPointer(Data);
+  }
+
+  inline bool operator==(const SVal& R) const {
+    return getRawKind() == R.getRawKind() && Data == R.Data;
+  }
+
+  inline bool operator!=(const SVal& R) const {
+    return !(*this == R);
+  }
+
+  inline bool isUnknown() const {
+    return getRawKind() == UnknownKind;
+  }
+
+  inline bool isUndef() const {
+    return getRawKind() == UndefinedKind;
+  }
+
+  inline bool isUnknownOrUndef() const {
+    return getRawKind() <= UnknownKind;
+  }
+
+  inline bool isValid() const {
+    return getRawKind() > UnknownKind;
+  }
+
+  bool isConstant() const;
+
+  bool isConstant(int I) const;
+
+  bool isZeroConstant() const;
+
+  /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
+  bool hasConjuredSymbol() const;
+
+  /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
+  /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
+  /// Otherwise return 0.
+  const FunctionDecl* getAsFunctionDecl() const;
+
+  /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+  ///  wraps a symbol, return that SymbolRef.  Otherwise return NULL.
+  SymbolRef getAsLocSymbol() const;
+
+  /// Get the symbol in the SVal or its base region.
+  SymbolRef getLocSymbolInBase() const;
+
+  /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
+  ///  Otherwise return a SymbolRef where 'isValid()' returns false.
+  SymbolRef getAsSymbol() const;
+
+  /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
+  ///  return that expression.  Otherwise return NULL.
+  const SymExpr *getAsSymbolicExpression() const;
+
+  const MemRegion *getAsRegion() const;
+
+  void dumpToStream(llvm::raw_ostream& OS) const;
+  void dump() const;
+
+  // Iterators.
+  class symbol_iterator {
+    llvm::SmallVector<const SymExpr*, 5> itr;
+    void expand();
+  public:
+    symbol_iterator() {}
+    symbol_iterator(const SymExpr* SE);
+
+    symbol_iterator& operator++();
+    SymbolRef operator*();
+
+    bool operator==(const symbol_iterator& X) const;
+    bool operator!=(const symbol_iterator& X) const;
+  };
+
+  symbol_iterator symbol_begin() const {
+    const SymExpr *SE = getAsSymbolicExpression();
+    if (SE)
+      return symbol_iterator(SE);
+    else
+      return symbol_iterator();
+  }
+
+  symbol_iterator symbol_end() const { return symbol_iterator(); }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal*) { return true; }
+};
+
+
+class UndefinedVal : public SVal {
+public:
+  UndefinedVal() : SVal(UndefinedKind) {}
+  UndefinedVal(const void* D) : SVal(UndefinedKind, D) {}
+
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == UndefinedKind;
+  }
+
+  const void* getData() const { return Data; }
+};
+
+class DefinedOrUnknownSVal : public SVal {
+private:
+  // Do not implement.  We want calling these methods to be a compiler
+  // error since they are tautologically false.
+  bool isUndef() const;
+  bool isValid() const;
+  
+protected:
+  explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
+    : SVal(d, isLoc, ValKind) {}
+  
+  explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
+    : SVal(k, D) {}
+  
+public:
+    // Implement isa<T> support.
+  static inline bool classof(const SVal *V) {
+    return !V->isUndef();
+  }
+};
+  
+class UnknownVal : public DefinedOrUnknownSVal {
+public:
+  explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
+  
+  static inline bool classof(const SVal *V) {
+    return V->getBaseKind() == UnknownKind;
+  }
+};
+
+class DefinedSVal : public DefinedOrUnknownSVal {
+private:
+  // Do not implement.  We want calling these methods to be a compiler
+  // error since they are tautologically true/false.
+  bool isUnknown() const;
+  bool isUnknownOrUndef() const;
+  bool isValid() const;  
+protected:
+  explicit DefinedSVal(const void* d, bool isLoc, unsigned ValKind)
+    : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+public:
+  // Implement isa<T> support.
+  static inline bool classof(const SVal *V) {
+    return !V->isUnknownOrUndef();
+  }
+};
+
+class NonLoc : public DefinedSVal {
+protected:
+  explicit NonLoc(unsigned SubKind, const void* d)
+    : DefinedSVal(d, false, SubKind) {}
+
+public:
+  void dumpToStream(llvm::raw_ostream& Out) const;
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == NonLocKind;
+  }
+};
+
+class Loc : public DefinedSVal {
+protected:
+  explicit Loc(unsigned SubKind, const void* D)
+  : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
+
+public:
+  void dumpToStream(llvm::raw_ostream& Out) const;
+
+  Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == LocKind;
+  }
+
+  static inline bool IsLocType(QualType T) {
+    return T->isAnyPointerType() || T->isBlockPointerType() || 
+           T->isReferenceType();
+  }
+};
+
+//==------------------------------------------------------------------------==//
+//  Subclasses of NonLoc.
+//==------------------------------------------------------------------------==//
+
+namespace nonloc {
+
+enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
+            LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+
+class SymbolVal : public NonLoc {
+public:
+  SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
+
+  SymbolRef getSymbol() const {
+    return (const SymbolData*) Data;
+  }
+
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == NonLocKind &&
+           V->getSubKind() == SymbolValKind;
+  }
+
+  static inline bool classof(const NonLoc* V) {
+    return V->getSubKind() == SymbolValKind;
+  }
+};
+
+class SymExprVal : public NonLoc {
+public:
+  explicit SymExprVal(const SymExpr *SE)
+    : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
+
+  const SymExpr *getSymbolicExpression() const {
+    return reinterpret_cast<const SymExpr*>(Data);
+  }
+
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == NonLocKind &&
+           V->getSubKind() == SymExprValKind;
+  }
+
+  static inline bool classof(const NonLoc* V) {
+    return V->getSubKind() == SymExprValKind;
+  }
+};
+
+class ConcreteInt : public NonLoc {
+public:
+  explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
+
+  const llvm::APSInt& getValue() const {
+    return *static_cast<const llvm::APSInt*>(Data);
+  }
+
+  // Transfer functions for binary/unary operations on ConcreteInts.
+  SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op,
+                 const ConcreteInt& R) const;
+
+  ConcreteInt evalComplement(SValBuilder &svalBuilder) const;
+
+  ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == NonLocKind &&
+           V->getSubKind() == ConcreteIntKind;
+  }
+
+  static inline bool classof(const NonLoc* V) {
+    return V->getSubKind() == ConcreteIntKind;
+  }
+};
+
+class LocAsInteger : public NonLoc {
+  friend class ento::SValBuilder;
+
+  explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
+    NonLoc(LocAsIntegerKind, &data) {
+      assert (isa<Loc>(data.first));
+    }
+
+public:
+
+  Loc getLoc() const {
+    return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
+  }
+
+  const Loc& getPersistentLoc() const {
+    const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
+    return cast<Loc>(V);
+  }
+
+  unsigned getNumBits() const {
+    return ((std::pair<SVal, unsigned>*) Data)->second;
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == NonLocKind &&
+           V->getSubKind() == LocAsIntegerKind;
+  }
+
+  static inline bool classof(const NonLoc* V) {
+    return V->getSubKind() == LocAsIntegerKind;
+  }
+};
+
+class CompoundVal : public NonLoc {
+  friend class ento::SValBuilder;
+
+  explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
+
+public:
+  const CompoundValData* getValue() const {
+    return static_cast<const CompoundValData*>(Data);
+  }
+
+  typedef llvm::ImmutableList<SVal>::iterator iterator;
+  iterator begin() const;
+  iterator end() const;
+
+  static bool classof(const SVal* V) {
+    return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
+  }
+
+  static bool classof(const NonLoc* V) {
+    return V->getSubKind() == CompoundValKind;
+  }
+};
+
+class LazyCompoundVal : public NonLoc {
+  friend class ento::SValBuilder;
+
+  explicit LazyCompoundVal(const LazyCompoundValData *D)
+    : NonLoc(LazyCompoundValKind, D) {}
+public:
+  const LazyCompoundValData *getCVData() const {
+    return static_cast<const LazyCompoundValData*>(Data);
+  }
+  const void *getStore() const;
+  const TypedRegion *getRegion() const;
+
+  static bool classof(const SVal *V) {
+    return V->getBaseKind() == NonLocKind &&
+           V->getSubKind() == LazyCompoundValKind;
+  }
+  static bool classof(const NonLoc *V) {
+    return V->getSubKind() == LazyCompoundValKind;
+  }
+};
+
+} // end namespace ento::nonloc
+
+//==------------------------------------------------------------------------==//
+//  Subclasses of Loc.
+//==------------------------------------------------------------------------==//
+
+namespace loc {
+
+enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
+
+class GotoLabel : public Loc {
+public:
+  explicit GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
+
+  const LabelStmt* getLabel() const {
+    return static_cast<const LabelStmt*>(Data);
+  }
+
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == LocKind &&
+           V->getSubKind() == GotoLabelKind;
+  }
+
+  static inline bool classof(const Loc* V) {
+    return V->getSubKind() == GotoLabelKind;
+  }
+};
+
+
+class MemRegionVal : public Loc {
+public:
+  explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
+
+  const MemRegion* getRegion() const {
+    return static_cast<const MemRegion*>(Data);
+  }
+
+  const MemRegion* StripCasts() const;
+
+  template <typename REGION>
+  const REGION* getRegionAs() const {
+    return llvm::dyn_cast<REGION>(getRegion());
+  }
+
+  inline bool operator==(const MemRegionVal& R) const {
+    return getRegion() == R.getRegion();
+  }
+
+  inline bool operator!=(const MemRegionVal& R) const {
+    return getRegion() != R.getRegion();
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == LocKind &&
+           V->getSubKind() == MemRegionKind;
+  }
+
+  static inline bool classof(const Loc* V) {
+    return V->getSubKind() == MemRegionKind;
+  }
+};
+
+class ConcreteInt : public Loc {
+public:
+  explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
+
+  const llvm::APSInt& getValue() const {
+    return *static_cast<const llvm::APSInt*>(Data);
+  }
+
+  // Transfer functions for binary/unary operations on ConcreteInts.
+  SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+                 const ConcreteInt& R) const;
+
+  // Implement isa<T> support.
+  static inline bool classof(const SVal* V) {
+    return V->getBaseKind() == LocKind &&
+           V->getSubKind() == ConcreteIntKind;
+  }
+
+  static inline bool classof(const Loc* V) {
+    return V->getSubKind() == ConcreteIntKind;
+  }
+};
+
+} // end ento::loc namespace
+} // end GR namespace
+
+} // end clang namespace
+
+namespace llvm {
+static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+                                            clang::ento::SVal V) {
+  V.dumpToStream(os);
+  return os;
+}
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/Store.h b/include/clang/StaticAnalyzer/PathSensitive/Store.h
new file mode 100644 (file)
index 0000000..c48f129
--- /dev/null
@@ -0,0 +1,259 @@
+//== Store.h - Interface for maps from Locations to 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 defined the types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_STORE_H
+#define LLVM_CLANG_GR_STORE_H
+
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+
+class Stmt;
+class Expr;
+class ObjCIvarDecl;
+class StackFrameContext;
+
+namespace ento {
+
+/// Store - This opaque type encapsulates an immutable mapping from
+///  locations to values.  At a high-level, it represents the symbolic
+///  memory model.  Different subclasses of StoreManager may choose
+///  different types to represent the locations and values.
+typedef const void* Store;
+
+class GRState;
+class GRStateManager;
+class SubRegionMap;
+
+class StoreManager {
+protected:
+  SValBuilder &svalBuilder;
+  GRStateManager &StateMgr;
+
+  /// MRMgr - Manages region objects associated with this StoreManager.
+  MemRegionManager &MRMgr;
+  ASTContext &Ctx;
+
+  StoreManager(GRStateManager &stateMgr);
+
+public:
+  virtual ~StoreManager() {}
+
+  /// Return the value bound to specified location in a given state.
+  /// \param[in] state The analysis state.
+  /// \param[in] loc The symbolic memory location.
+  /// \param[in] T An optional type that provides a hint indicating the
+  ///   expected type of the returned value.  This is used if the value is
+  ///   lazily computed.
+  /// \return The value bound to the location \c loc.
+  virtual SVal Retrieve(Store store, Loc loc, QualType T = QualType()) = 0;
+
+  /// Return a state with the specified value bound to the given location.
+  /// \param[in] state The analysis state.
+  /// \param[in] loc The symbolic memory location.
+  /// \param[in] val The value to bind to location \c loc.
+  /// \return A pointer to a GRState object that contains the same bindings as
+  ///   \c state with the addition of having the value specified by \c val bound
+  ///   to the location given for \c loc.
+  virtual Store Bind(Store store, Loc loc, SVal val) = 0;
+
+  virtual Store BindDefault(Store store, const MemRegion *R, SVal V) {
+    return store;
+  }
+
+  virtual Store Remove(Store St, Loc L) = 0;
+
+  /// BindCompoundLiteral - Return the store that has the bindings currently
+  ///  in 'store' plus the bindings for the CompoundLiteral.  'R' is the region
+  ///  for the compound literal and 'BegInit' and 'EndInit' represent an
+  ///  array of initializer values.
+  virtual Store BindCompoundLiteral(Store store,
+                                    const CompoundLiteralExpr* cl,
+                                    const LocationContext *LC, SVal v) = 0;
+
+  /// getInitialStore - Returns the initial "empty" store representing the
+  ///  value bindings upon entry to an analyzed function.
+  virtual Store getInitialStore(const LocationContext *InitLoc) = 0;
+
+  /// getRegionManager - Returns the internal RegionManager object that is
+  ///  used to query and manipulate MemRegion objects.
+  MemRegionManager& getRegionManager() { return MRMgr; }
+
+  /// getSubRegionMap - Returns an opaque map object that clients can query
+  ///  to get the subregions of a given MemRegion object.  It is the
+  //   caller's responsibility to 'delete' the returned map.
+  virtual SubRegionMap *getSubRegionMap(Store store) = 0;
+
+  virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) {
+    return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC));
+  }
+
+  virtual Loc getLValueString(const StringLiteral* S) {
+    return svalBuilder.makeLoc(MRMgr.getStringRegion(S));
+  }
+
+  Loc getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+                               const LocationContext *LC) {
+    return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+  }
+
+  virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) {
+    return getLValueFieldOrIvar(decl, base);
+  }
+
+  virtual SVal getLValueField(const FieldDecl* D, SVal Base) {
+    return getLValueFieldOrIvar(D, Base);
+  }
+
+  virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base);
+
+  // FIXME: This should soon be eliminated altogether; clients should deal with
+  // region extents directly.
+  virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state, 
+                                                 const MemRegion *region,
+                                                 QualType EleTy) {
+    return UnknownVal();
+  }
+
+  /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
+  ///  conversions between arrays and pointers.
+  virtual SVal ArrayToPointer(Loc Array) = 0;
+
+  /// Evaluates DerivedToBase casts.
+  virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) {
+    return UnknownVal();
+  }
+
+  class CastResult {
+    const GRState *state;
+    const MemRegion *region;
+  public:
+    const GRState *getState() const { return state; }
+    const MemRegion* getRegion() const { return region; }
+    CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){}
+  };
+
+  const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
+
+  /// CastRegion - Used by ExprEngine::VisitCast to handle casts from
+  ///  a MemRegion* to a specific location type.  'R' is the region being
+  ///  casted and 'CastToTy' the result type of the cast.
+  const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy);
+
+
+  /// evalBinOp - Perform pointer arithmetic.
+  virtual SVal evalBinOp(BinaryOperator::Opcode Op,
+                         Loc lhs, NonLoc rhs, QualType resultTy) {
+    return UnknownVal();
+  }
+
+  virtual Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx,
+                                   SymbolReaper& SymReaper,
+                      llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
+
+  virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
+
+  virtual Store BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
+
+  typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+  typedef llvm::SmallVector<const MemRegion *, 8> InvalidatedRegions;
+
+  /// InvalidateRegions - Clears out the specified regions from the store,
+  ///  marking their values as unknown. Depending on the store, this may also
+  ///  invalidate additional regions that may have changed based on accessing
+  ///  the given regions. Optionally, invalidates non-static globals as well.
+  /// \param[in] store The initial store
+  /// \param[in] Begin A pointer to the first region to invalidate.
+  /// \param[in] End A pointer just past the last region to invalidate.
+  /// \param[in] E The current statement being evaluated. Used to conjure
+  ///   symbols to mark the values of invalidated regions.
+  /// \param[in] Count The current block count. Used to conjure
+  ///   symbols to mark the values of invalidated regions.
+  /// \param[in,out] IS A set to fill with any symbols that are no longer
+  ///   accessible. Pass \c NULL if this information will not be used.
+  /// \param[in] invalidateGlobals If \c true, any non-static global regions
+  ///   are invalidated as well.
+  /// \param[in,out] Regions A vector to fill with any regions being
+  ///   invalidated. This should include any regions explicitly invalidated
+  ///   even if they do not currently have bindings. Pass \c NULL if this
+  ///   information will not be used.
+  virtual Store InvalidateRegions(Store store,
+                                  const MemRegion * const *Begin,
+                                  const MemRegion * const *End,
+                                  const Expr *E, unsigned Count,
+                                  InvalidatedSymbols *IS,
+                                  bool invalidateGlobals,
+                                  InvalidatedRegions *Regions) = 0;
+
+  /// EnterStackFrame - Let the StoreManager to do something when execution
+  /// engine is about to execute into a callee.
+  virtual Store EnterStackFrame(const GRState *state,
+                                const StackFrameContext *frame);
+
+  virtual void print(Store store, llvm::raw_ostream& Out,
+                     const char* nl, const char *sep) = 0;
+
+  class BindingsHandler {
+  public:
+    virtual ~BindingsHandler();
+    virtual bool HandleBinding(StoreManager& SMgr, Store store,
+                               const MemRegion *region, SVal val) = 0;
+  };
+
+  /// iterBindings - Iterate over the bindings in the Store.
+  virtual void iterBindings(Store store, BindingsHandler& f) = 0;
+
+protected:
+  const MemRegion *MakeElementRegion(const MemRegion *baseRegion,
+                                     QualType pointeeTy, uint64_t index = 0);
+
+  /// CastRetrievedVal - Used by subclasses of StoreManager to implement
+  ///  implicit casts that arise from loads from regions that are reinterpreted
+  ///  as another region.
+  SVal CastRetrievedVal(SVal val, const TypedRegion *region, QualType castTy,
+                        bool performTestOnly = true);
+
+private:
+  SVal getLValueFieldOrIvar(const Decl* decl, SVal base);
+};
+
+// FIXME: Do we still need this?
+/// SubRegionMap - An abstract interface that represents a queryable map
+///  between MemRegion objects and their subregions.
+class SubRegionMap {
+public:
+  virtual ~SubRegionMap() {}
+
+  class Visitor {
+  public:
+    virtual ~Visitor() {}
+    virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0;
+  };
+
+  virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
+};
+
+// FIXME: Do we need to pass GRStateManager anymore?
+StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
+StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
+StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
+StoreManager *CreateFlatStoreManager(GRStateManager &StMgr);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/PathSensitive/SubEngine.h
new file mode 100644 (file)
index 0000000..8672bd1
--- /dev/null
@@ -0,0 +1,113 @@
+//== SubEngine.h - Interface of the subengine of CoreEngine --------*- 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 interface of a subengine of the CoreEngine.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_GR_SUBENGINE_H
+#define LLVM_CLANG_GR_SUBENGINE_H
+
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+
+namespace clang {
+
+class CFGBlock;
+class CFGElement;
+class LocationContext;
+class Stmt;
+
+namespace ento {
+
+class AnalysisManager;
+class ExplodedNode;
+class GRState;
+class GRStateManager;
+class BlockCounter;
+class StmtNodeBuilder;
+class BranchNodeBuilder;
+class IndirectGotoNodeBuilder;
+class SwitchNodeBuilder;
+class EndPathNodeBuilder;
+class CallEnterNodeBuilder;
+class CallExitNodeBuilder;
+class MemRegion;
+
+class SubEngine {
+public:
+  virtual ~SubEngine() {}
+
+  virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
+
+  virtual AnalysisManager &getAnalysisManager() = 0;
+
+  virtual GRStateManager &getStateManager() = 0;
+
+  /// Called by CoreEngine. Used to generate new successor
+  /// nodes by processing the 'effects' of a block-level statement.
+  virtual void ProcessElement(const CFGElement E, StmtNodeBuilder& builder)=0;
+
+  /// Called by CoreEngine when start processing
+  /// a CFGBlock.  This method returns true if the analysis should continue
+  /// exploring the given path, and false otherwise.
+  virtual bool ProcessBlockEntrance(const CFGBlock* B, const ExplodedNode *Pred,
+                                    BlockCounter BC) = 0;
+
+  /// Called by CoreEngine.  Used to generate successor
+  ///  nodes by processing the 'effects' of a branch condition.
+  virtual void ProcessBranch(const Stmt* Condition, const Stmt* Term,
+                             BranchNodeBuilder& builder) = 0;
+
+  /// Called by CoreEngine.  Used to generate successor
+  /// nodes by processing the 'effects' of a computed goto jump.
+  virtual void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) = 0;
+
+  /// Called by CoreEngine.  Used to generate successor
+  /// nodes by processing the 'effects' of a switch statement.
+  virtual void ProcessSwitch(SwitchNodeBuilder& builder) = 0;
+
+  /// ProcessEndPath - Called by CoreEngine.  Used to generate end-of-path
+  ///  nodes when the control reaches the end of a function.
+  virtual void ProcessEndPath(EndPathNodeBuilder& builder) = 0;
+
+  // Generate the entry node of the callee.
+  virtual void ProcessCallEnter(CallEnterNodeBuilder &builder) = 0;
+
+  // Generate the first post callsite node.
+  virtual void ProcessCallExit(CallExitNodeBuilder &builder) = 0;
+
+  /// Called by ConstraintManager. Used to call checker-specific
+  /// logic for handling assumptions on symbolic values.
+  virtual const GRState* ProcessAssume(const GRState *state,
+                                       SVal cond, bool assumption) = 0;
+
+  /// WantsRegionChangeUpdate - Called by GRStateManager to determine if a
+  ///  region change should trigger a ProcessRegionChanges update.
+  virtual bool WantsRegionChangeUpdate(const GRState* state) = 0;
+
+  /// ProcessRegionChanges - Called by GRStateManager whenever a change is made
+  ///  to the store. Used to update checkers that track region values.
+  virtual const GRState* ProcessRegionChanges(const GRState* state,
+                                              const MemRegion* const *Begin,
+                                              const MemRegion* const *End) = 0;
+
+  inline const GRState* ProcessRegionChange(const GRState* state,
+                                            const MemRegion* MR) {
+    return ProcessRegionChanges(state, &MR, &MR+1);
+  }
+
+  /// Called by CoreEngine when the analysis worklist is either empty or the
+  //  maximum number of analysis steps have been reached.
+  virtual void ProcessEndWorklist(bool hasWorkRemaining) = 0;
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/SummaryManager.h b/include/clang/StaticAnalyzer/PathSensitive/SummaryManager.h
new file mode 100644 (file)
index 0000000..ed87851
--- /dev/null
@@ -0,0 +1,61 @@
+//== SummaryManager.h - Generic handling of function summaries --*- 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 SummaryManager and related classes, which provides
+//  a generic mechanism for managing function summaries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_SUMMARY
+#define LLVM_CLANG_GR_SUMMARY
+
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+
+namespace ento {
+
+namespace summMgr {
+
+  
+/* Key kinds:
+ - C functions
+ - C++ functions (name + parameter types)
+ - ObjC methods:
+   - Class, selector (class method)
+   - Class, selector (instance method)
+   - Category, selector (instance method)
+   - Protocol, selector (instance method)
+ - C++ methods
+  - Class, function name + parameter types + const
+ */
+  
+class SummaryKey {
+  
+};
+
+} // end namespace clang::summMgr
+  
+class SummaryManagerImpl {
+  
+};
+
+  
+template <typename T>
+class SummaryManager : SummaryManagerImpl {
+  
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/PathSensitive/SymbolManager.h
new file mode 100644 (file)
index 0000000..ad173bb
--- /dev/null
@@ -0,0 +1,489 @@
+//== SymbolManager.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 SymbolManager, a class that manages symbolic values
+//  created for use by ExprEngine and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_SYMMGR_H
+#define LLVM_CLANG_GR_SYMMGR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace llvm {
+class BumpPtrAllocator;
+class raw_ostream;
+}
+
+namespace clang {
+  class ASTContext;
+  class StackFrameContext;
+
+namespace ento {
+  class BasicValueFactory;
+  class MemRegion;
+  class SubRegion;
+  class TypedRegion;
+  class VarRegion;
+
+class SymExpr : public llvm::FoldingSetNode {
+public:
+  enum Kind { BEGIN_SYMBOLS,
+              RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
+              MetadataKind,
+              END_SYMBOLS,
+              SymIntKind, SymSymKind };
+private:
+  Kind K;
+
+protected:
+  SymExpr(Kind k) : K(k) {}
+
+public:
+  virtual ~SymExpr() {}
+
+  Kind getKind() const { return K; }
+
+  void dump() const;
+
+  virtual void dumpToStream(llvm::raw_ostream &os) const = 0;
+
+  virtual QualType getType(ASTContext&) const = 0;
+  virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr*) { return true; }
+};
+
+typedef unsigned SymbolID;
+
+class SymbolData : public SymExpr {
+private:
+  const SymbolID Sym;
+
+protected:
+  SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+
+public:
+  virtual ~SymbolData() {}
+
+  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;
+  }
+};
+
+typedef const SymbolData* SymbolRef;
+
+// A symbol representing the value of a MemRegion.
+class SymbolRegionValue : public SymbolData {
+  const TypedRegion *R;
+
+public:
+  SymbolRegionValue(SymbolID sym, const TypedRegion *r)
+    : SymbolData(RegionValueKind, sym), R(r) {}
+
+  const TypedRegion* getRegion() const { return R; }
+
+  static void Profile(llvm::FoldingSetNodeID& profile, const TypedRegion* R) {
+    profile.AddInteger((unsigned) RegionValueKind);
+    profile.AddPointer(R);
+  }
+
+  virtual void Profile(llvm::FoldingSetNodeID& profile) {
+    Profile(profile, R);
+  }
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  QualType getType(ASTContext&) const;
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == RegionValueKind;
+  }
+};
+
+// A symbol representing the result of an expression.
+class SymbolConjured : public SymbolData {
+  const Stmt* S;
+  QualType T;
+  unsigned Count;
+  const void* SymbolTag;
+
+public:
+  SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count,
+                 const void* symbolTag)
+    : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
+      SymbolTag(symbolTag) {}
+
+  const Stmt* getStmt() const { return S; }
+  unsigned getCount() const { return Count; }
+  const void* getTag() const { return SymbolTag; }
+
+  QualType getType(ASTContext&) const;
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S,
+                      QualType T, unsigned Count, const void* SymbolTag) {
+    profile.AddInteger((unsigned) ConjuredKind);
+    profile.AddPointer(S);
+    profile.Add(T);
+    profile.AddInteger(Count);
+    profile.AddPointer(SymbolTag);
+  }
+
+  virtual void Profile(llvm::FoldingSetNodeID& profile) {
+    Profile(profile, S, T, Count, SymbolTag);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == ConjuredKind;
+  }
+};
+
+// A symbol representing the value of a MemRegion whose parent region has 
+// symbolic value.
+class SymbolDerived : public SymbolData {
+  SymbolRef parentSymbol;
+  const TypedRegion *R;
+
+public:
+  SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
+    : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
+
+  SymbolRef getParentSymbol() const { return parentSymbol; }
+  const TypedRegion *getRegion() const { return R; }
+
+  QualType getType(ASTContext&) const;
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
+                      const TypedRegion *r) {
+    profile.AddInteger((unsigned) DerivedKind);
+    profile.AddPointer(r);
+    profile.AddPointer(parent);
+  }
+
+  virtual void Profile(llvm::FoldingSetNodeID& profile) {
+    Profile(profile, parentSymbol, R);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == DerivedKind;
+  }
+};
+
+/// SymbolExtent - Represents the extent (size in bytes) of a bounded region.
+///  Clients should not ask the SymbolManager for a region's extent. Always use
+///  SubRegion::getExtent instead -- the value returned may not be a symbol.
+class SymbolExtent : public SymbolData {
+  const SubRegion *R;
+  
+public:
+  SymbolExtent(SymbolID sym, const SubRegion *r)
+  : SymbolData(ExtentKind, sym), R(r) {}
+
+  const SubRegion *getRegion() const { return R; }
+
+  QualType getType(ASTContext&) const;
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
+    profile.AddInteger((unsigned) ExtentKind);
+    profile.AddPointer(R);
+  }
+
+  virtual void Profile(llvm::FoldingSetNodeID& profile) {
+    Profile(profile, R);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == ExtentKind;
+  }
+};
+
+/// SymbolMetadata - Represents path-dependent metadata about a specific region.
+///  Metadata symbols remain live as long as they are marked as in use before
+///  dead-symbol sweeping AND their associated regions are still alive.
+///  Intended for use by checkers.
+class SymbolMetadata : public SymbolData {
+  const MemRegion* R;
+  const Stmt* S;
+  QualType T;
+  unsigned Count;
+  const void* Tag;
+public:
+  SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt* s, QualType t,
+                 unsigned count, const void* tag)
+  : SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
+
+  const MemRegion *getRegion() const { return R; }
+  const Stmt* getStmt() const { return S; }
+  unsigned getCount() const { return Count; }
+  const void* getTag() const { return Tag; }
+
+  QualType getType(ASTContext&) const;
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
+                      const Stmt *S, QualType T, unsigned Count,
+                      const void *Tag) {
+    profile.AddInteger((unsigned) MetadataKind);
+    profile.AddPointer(R);
+    profile.AddPointer(S);
+    profile.Add(T);
+    profile.AddInteger(Count);
+    profile.AddPointer(Tag);
+  }
+
+  virtual void Profile(llvm::FoldingSetNodeID& profile) {
+    Profile(profile, R, S, T, Count, Tag);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == MetadataKind;
+  }
+};
+
+// SymIntExpr - Represents symbolic expression like 'x' + 3.
+class SymIntExpr : public SymExpr {
+  const SymExpr *LHS;
+  BinaryOperator::Opcode Op;
+  const llvm::APSInt& RHS;
+  QualType T;
+
+public:
+  SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+             const llvm::APSInt& rhs, QualType t)
+    : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+  // FIXME: We probably need to make this out-of-line to avoid redundant
+  // generation of virtual functions.
+  QualType getType(ASTContext& C) const { return T; }
+
+  BinaryOperator::Opcode getOpcode() const { return Op; }
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  const SymExpr *getLHS() const { return LHS; }
+  const llvm::APSInt &getRHS() const { return RHS; }
+
+  static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+                      BinaryOperator::Opcode op, const llvm::APSInt& rhs,
+                      QualType t) {
+    ID.AddInteger((unsigned) SymIntKind);
+    ID.AddPointer(lhs);
+    ID.AddInteger(op);
+    ID.AddPointer(&rhs);
+    ID.Add(t);
+  }
+
+  void Profile(llvm::FoldingSetNodeID& ID) {
+    Profile(ID, LHS, Op, RHS, T);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == SymIntKind;
+  }
+};
+
+// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
+class SymSymExpr : public SymExpr {
+  const SymExpr *LHS;
+  BinaryOperator::Opcode Op;
+  const SymExpr *RHS;
+  QualType T;
+
+public:
+  SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
+             QualType t)
+    : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+  BinaryOperator::Opcode getOpcode() const { return Op; }
+  const SymExpr *getLHS() const { return LHS; }
+  const SymExpr *getRHS() const { return RHS; }
+
+  // FIXME: We probably need to make this out-of-line to avoid redundant
+  // generation of virtual functions.
+  QualType getType(ASTContext& C) const { return T; }
+
+  void dumpToStream(llvm::raw_ostream &os) const;
+
+  static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+                    BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
+    ID.AddInteger((unsigned) SymSymKind);
+    ID.AddPointer(lhs);
+    ID.AddInteger(op);
+    ID.AddPointer(rhs);
+    ID.Add(t);
+  }
+
+  void Profile(llvm::FoldingSetNodeID& ID) {
+    Profile(ID, LHS, Op, RHS, T);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr* SE) {
+    return SE->getKind() == SymSymKind;
+  }
+};
+
+class SymbolManager {
+  typedef llvm::FoldingSet<SymExpr> DataSetTy;
+  DataSetTy DataSet;
+  unsigned SymbolCounter;
+  llvm::BumpPtrAllocator& BPAlloc;
+  BasicValueFactory &BV;
+  ASTContext& Ctx;
+
+public:
+  SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
+                llvm::BumpPtrAllocator& bpalloc)
+    : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
+
+  ~SymbolManager();
+
+  static bool canSymbolicate(QualType T);
+
+  /// Make a unique symbol for MemRegion R according to its kind.
+  const SymbolRegionValue* getRegionValueSymbol(const TypedRegion* R);
+
+  const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+                                          unsigned VisitCount,
+                                          const void* SymbolTag = 0);
+
+  const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
+                                          const void* SymbolTag = 0) {
+    return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
+  }
+
+  const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
+                                        const TypedRegion *R);
+
+  const SymbolExtent *getExtentSymbol(const SubRegion *R);
+
+  const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt* S,
+                                          QualType T, unsigned VisitCount,
+                                          const void* SymbolTag = 0);
+
+  const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+                                  const llvm::APSInt& rhs, QualType t);
+
+  const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op,
+                                  const llvm::APSInt& rhs, QualType t) {
+    return getSymIntExpr(&lhs, op, rhs, t);
+  }
+
+  const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+                                  const SymExpr *rhs, QualType t);
+
+  QualType getType(const SymExpr *SE) const {
+    return SE->getType(Ctx);
+  }
+
+  ASTContext &getContext() { return Ctx; }
+  BasicValueFactory &getBasicVals() { return BV; }
+};
+
+class SymbolReaper {
+  typedef llvm::DenseSet<SymbolRef> SetTy;
+
+  SetTy TheLiving;
+  SetTy MetadataInUse;
+  SetTy TheDead;
+  const LocationContext *LCtx;
+  const Stmt *Loc;
+  SymbolManager& SymMgr;
+
+public:
+  SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr)
+   : LCtx(ctx), Loc(s), SymMgr(symmgr) {}
+
+  ~SymbolReaper() {}
+
+  const LocationContext *getLocationContext() const { return LCtx; }
+  const Stmt *getCurrentStatement() const { return Loc; }
+
+  bool isLive(SymbolRef sym);
+  bool isLive(const Stmt *ExprVal) const;
+  bool isLive(const VarRegion *VR) const;
+
+  // markLive - Unconditionally marks a symbol as live. This should never be
+  //  used by checkers, only by the state infrastructure such as the store and
+  //  environment. Checkers should instead use metadata symbols and markInUse.
+  void markLive(SymbolRef sym);
+
+  // markInUse - Marks a symbol as important to a checker. For metadata symbols,
+  //  this will keep the symbol alive as long as its associated region is also
+  //  live. For other symbols, this has no effect; checkers are not permitted
+  //  to influence the life of other symbols. This should be used before any
+  //  symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
+  void markInUse(SymbolRef sym);
+
+  // maybeDead - If a symbol is known to be live, marks the symbol as live.
+  //  Otherwise, if the symbol cannot be proven live, it is marked as dead.
+  //  Returns true if the symbol is dead, false if live.
+  bool maybeDead(SymbolRef sym);
+
+  typedef SetTy::const_iterator dead_iterator;
+  dead_iterator dead_begin() const { return TheDead.begin(); }
+  dead_iterator dead_end() const { return TheDead.end(); }
+
+  bool hasDeadSymbols() const {
+    return !TheDead.empty();
+  }
+
+  /// isDead - Returns whether or not a symbol has been confirmed dead. This
+  ///  should only be called once all marking of dead symbols has completed.
+  ///  (For checkers, this means only in the evalDeadSymbols callback.)
+  bool isDead(SymbolRef sym) const {
+    return TheDead.count(sym);
+  }
+};
+
+class SymbolVisitor {
+public:
+  // VisitSymbol - A visitor method invoked by
+  //  GRStateManager::scanReachableSymbols.  The method returns \c true if
+  //  symbols should continue be scanned and \c false otherwise.
+  virtual bool VisitSymbol(SymbolRef sym) = 0;
+  virtual ~SymbolVisitor();
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+namespace llvm {
+static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+                                            const clang::ento::SymExpr *SE) {
+  SE->dumpToStream(os);
+  return os;
+}
+} // end llvm namespace
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h b/include/clang/StaticAnalyzer/PathSensitive/TransferFuncs.h
new file mode 100644 (file)
index 0000000..22e3a4d
--- /dev/null
@@ -0,0 +1,92 @@
+//== TransferFuncs.h - Path-Sens. Transfer Functions Interface ---*- 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 TransferFuncs, which provides a base-class that
+//  defines an interface for transfer functions used by ExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_TRANSFERFUNCS
+#define LLVM_CLANG_GR_TRANSFERFUNCS
+
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include <vector>
+
+namespace clang {
+class ObjCMessageExpr;
+
+namespace ento {
+class ExplodedNode;
+class ExplodedNodeSet;
+class EndPathNodeBuilder;
+class ExprEngine;
+class StmtNodeBuilder;
+class StmtNodeBuilderRef;
+
+class TransferFuncs {
+public:
+  TransferFuncs() {}
+  virtual ~TransferFuncs() {}
+
+  virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
+  virtual void RegisterChecks(ExprEngine& Eng) {}
+
+
+  // Calls.
+
+  virtual void evalCall(ExplodedNodeSet& Dst,
+                        ExprEngine& Engine,
+                        StmtNodeBuilder& Builder,
+                        const CallExpr* CE, SVal L,
+                        ExplodedNode* Pred) {}
+
+  virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
+                                   ExprEngine& Engine,
+                                   StmtNodeBuilder& Builder,
+                                   const ObjCMessageExpr* ME,
+                                   ExplodedNode* Pred,
+                                   const GRState *state) {}
+
+  // Stores.
+
+  virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {}
+
+  // End-of-path and dead symbol notification.
+
+  virtual void evalEndPath(ExprEngine& Engine,
+                           EndPathNodeBuilder& Builder) {}
+
+
+  virtual void evalDeadSymbols(ExplodedNodeSet& Dst,
+                               ExprEngine& Engine,
+                               StmtNodeBuilder& Builder,
+                               ExplodedNode* Pred,
+                               const GRState* state,
+                               SymbolReaper& SymReaper) {}
+
+  // Return statements.
+  virtual void evalReturn(ExplodedNodeSet& Dst,
+                          ExprEngine& Engine,
+                          StmtNodeBuilder& Builder,
+                          const ReturnStmt* S,
+                          ExplodedNode* Pred) {}
+
+  // Assumptions.
+  virtual const GRState* evalAssume(const GRState *state,
+                                    SVal Cond, bool Assumption) {
+    return state;
+  }  
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/PathSensitive/WorkList.h
new file mode 100644 (file)
index 0000000..be90906
--- /dev/null
@@ -0,0 +1,94 @@
+//==- WorkList.h - Worklist class used by CoreEngine ---------------*- 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 WorkList, a pure virtual class that represents an opaque
+//  worklist used by CoreEngine to explore the reachability state space.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_WORKLIST
+#define LLVM_CLANG_GR_WORKLIST
+
+#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
+#include <cstddef>
+
+namespace clang {
+  
+class CFGBlock;
+
+namespace ento {
+
+class ExplodedNode;
+class ExplodedNodeImpl;
+
+class WorkListUnit {
+  ExplodedNode* Node;
+  BlockCounter Counter;
+  const CFGBlock* Block;
+  unsigned BlockIdx; // This is the index of the next statement.
+
+public:
+  WorkListUnit(ExplodedNode* N, BlockCounter C,
+                 const CFGBlock* B, unsigned idx)
+  : Node(N),
+    Counter(C),
+    Block(B),
+    BlockIdx(idx) {}
+
+  explicit WorkListUnit(ExplodedNode* N, BlockCounter C)
+  : Node(N),
+    Counter(C),
+    Block(NULL),
+    BlockIdx(0) {}
+
+  ExplodedNode* getNode()         const { return Node; }
+  BlockCounter    getBlockCounter() const { return Counter; }
+  const CFGBlock*   getBlock()        const { return Block; }
+  unsigned          getIndex()        const { return BlockIdx; }
+};
+
+class WorkList {
+  BlockCounter CurrentCounter;
+public:
+  virtual ~WorkList();
+  virtual bool hasWork() const = 0;
+
+  virtual void Enqueue(const WorkListUnit& U) = 0;
+
+  void Enqueue(ExplodedNode* N, const CFGBlock* B, unsigned idx) {
+    Enqueue(WorkListUnit(N, CurrentCounter, B, idx));
+  }
+
+  void Enqueue(ExplodedNode* N) {
+    Enqueue(WorkListUnit(N, CurrentCounter));
+  }
+
+  virtual WorkListUnit Dequeue() = 0;
+
+  void setBlockCounter(BlockCounter C) { CurrentCounter = C; }
+  BlockCounter getBlockCounter() const { return CurrentCounter; }
+
+  class Visitor {
+  public:
+    Visitor() {}
+    virtual ~Visitor();
+    virtual bool Visit(const WorkListUnit &U) = 0;
+  };
+  virtual bool VisitItemsInWorkList(Visitor &V) = 0;
+  
+  static WorkList *MakeDFS();
+  static WorkList *MakeBFS();
+  static WorkList *MakeBFSBlockDFSContents();
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
index 6197dc72d0ba571ae57cf56213b69ecd8a30bd99..a75dd22386b5e6a2756e1585df4f000a27ac30f2 100644 (file)
@@ -12,5 +12,5 @@ add_subdirectory(Serialization)
 add_subdirectory(Frontend)
 add_subdirectory(FrontendTool)
 add_subdirectory(Index)
-add_subdirectory(EntoSA)
-add_subdirectory(EntoSA/Checkers)
+add_subdirectory(StaticAnalyzer)
+add_subdirectory(StaticAnalyzer/Checkers)
index 89937e1762ce9b87576ff5e604803011f50b5060..31983df365256663dc2ed7cce6f985c553f343d4 100644 (file)
@@ -1,7 +1,7 @@
 set(LLVM_NO_RTTI 1)
 
 set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen 
-    clangEntoCheckers clangEntoCore)
+    clangStaticAnalyzerCheckers clangStaticAnalyzerCore)
 
 add_clang_library(clangFrontendTool
   ExecuteCompilerInvocation.cpp
index e17e8b715685de8cb8eeea8a14de5ed2ab547501..6278975b75ba14314e379e5cf03db515a2f98ed1 100644 (file)
@@ -13,7 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/FrontendTool/Utils.h"
-#include "clang/EntoSA/FrontendActions.h"
+#include "clang/StaticAnalyzer/FrontendActions.h"
 #include "clang/CodeGen/CodeGenAction.h"
 #include "clang/Driver/CC1Options.h"
 #include "clang/Driver/OptTable.h"
index 300b9ea09714aa51850534ef93ed5315756047f0..bf357fc7d569e5900e168d8880aa6e01aef863fe 100755 (executable)
@@ -9,7 +9,7 @@
 CLANG_LEVEL := ..
 
 PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
-                EntoSA Rewrite Serialization Frontend FrontendTool Index Driver
+                StaticAnalyzer Rewrite Serialization Frontend FrontendTool Index Driver
 
 include $(CLANG_LEVEL)/Makefile
 
similarity index 97%
rename from lib/EntoSA/AggExprVisitor.cpp
rename to lib/StaticAnalyzer/AggExprVisitor.cpp
index c356186622633bb228da2ab3529fe26fa47e4065..0cc23900ed0fcb7cc931ce3082224e603c5a9506 100644 (file)
@@ -12,7 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/AST/StmtVisitor.h"
 
 using namespace clang;
similarity index 94%
rename from lib/EntoSA/AnalysisManager.cpp
rename to lib/StaticAnalyzer/AnalysisManager.cpp
index fa64f472f78ae2dad095e994baaebfe4c944c32b..cc5e271393447895b738d9af01653c9677db55a8 100644 (file)
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
 #include "clang/Index/Entity.h"
 #include "clang/Index/Indexer.h"
 
similarity index 95%
rename from lib/EntoSA/AnalyzerStatsChecker.cpp
rename to lib/StaticAnalyzer/AnalyzerStatsChecker.cpp
index fb0e74b4b5261813e1c40978baa9539dd31dcdd4..8521c18c5480d2e11e4d26e1f9167ecc6b4c5786 100644 (file)
@@ -9,9 +9,9 @@
 // This file reports various statistics about analyzer visitation.
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 
 // FIXME: Restructure checker registration.
 #include "Checkers/ExprEngineExperimentalChecks.h"
similarity index 98%
rename from lib/EntoSA/BasicConstraintManager.cpp
rename to lib/StaticAnalyzer/BasicConstraintManager.cpp
index 92837d2ff4d74505a7b973fb0b9c762c89564d17..8bdc4fa00306deb7edf96c239ae42db4ba20d98b 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "SimpleConstraintManager.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
similarity index 99%
rename from lib/EntoSA/BasicStore.cpp
rename to lib/StaticAnalyzer/BasicStore.cpp
index 8c4a732aa31f33b2e1fa80d53d8b6b9f33324661..35bcf945fb93d7a1421ce4d84350953d67a30ed1 100644 (file)
@@ -15,7 +15,7 @@
 #include "clang/AST/ExprObjC.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/AnalysisContext.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "llvm/ADT/ImmutableMap.h"
 
 using namespace clang;
similarity index 99%
rename from lib/EntoSA/BasicValueFactory.cpp
rename to lib/StaticAnalyzer/BasicValueFactory.cpp
index 0d1cb4a91339613d6fd21c2eb36cbccbdfc75aeb..d8b501bc7c5f5725885585d5c2edd20570ab6ed9 100644 (file)
@@ -13,7 +13,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
 
 using namespace clang;
 using namespace ento;
similarity index 97%
rename from lib/EntoSA/BlockCounter.cpp
rename to lib/StaticAnalyzer/BlockCounter.cpp
index b4e6eeee3f4ddc08adb55461c5470acb9868c2fc..47f6088a47fb5ca6600324ada51fb0c7bf90e769 100644 (file)
@@ -13,7 +13,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/BlockCounter.h"
+#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
 #include "llvm/ADT/ImmutableMap.h"
 
 using namespace clang;
similarity index 99%
rename from lib/EntoSA/BugReporter.cpp
rename to lib/StaticAnalyzer/BugReporter.cpp
index ff3502449993aeab014889fd8568b98d5bfcf02d..8edbe14878e807001fe0dafddd78e2a6644ed49c 100644 (file)
@@ -12,9 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Analysis/CFG.h"
 #include "clang/AST/Expr.h"
@@ -22,7 +22,7 @@
 #include "clang/AST/StmtObjC.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Analysis/ProgramPoint.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
similarity index 98%
rename from lib/EntoSA/BugReporterVisitors.cpp
rename to lib/StaticAnalyzer/BugReporterVisitors.cpp
index d264505b23f5c3bfbdb82b57e57666af8c5931cc..91d727592c9c84595e1c0a834a2e0e728cf22ebf 100644 (file)
 
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
-#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 
 using namespace clang;
 using namespace ento;
similarity index 99%
rename from lib/EntoSA/CFRefCount.cpp
rename to lib/StaticAnalyzer/CFRefCount.cpp
index 9c9637eb821a87450f0e19c5dd1b12a60d1d706a..5fd223c471166d9c987a7297bea23e811024302c 100644 (file)
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceManager.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngineBuilders.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
-#include "clang/EntoSA/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
similarity index 85%
rename from lib/EntoSA/CMakeLists.txt
rename to lib/StaticAnalyzer/CMakeLists.txt
index 09a6c2f364356668408bb61b2bdd089a9af9c5c8..cf81e1d5ad89f783309b53b4d968a5e7778b53c5 100644 (file)
@@ -2,7 +2,7 @@ set(LLVM_NO_RTTI 1)
 
 set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
 
-add_clang_library(clangEntoCore
+add_clang_library(clangStaticAnalyzerCore
   AggExprVisitor.cpp
   AnalysisManager.cpp
   AnalyzerStatsChecker.cpp
@@ -37,5 +37,5 @@ add_clang_library(clangEntoCore
   TextPathDiagnostics.cpp
   )
 
-add_dependencies(clangEntoCore ClangAttrClasses ClangAttrList ClangDeclNodes
+add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
                  ClangStmtNodes)
similarity index 99%
rename from lib/EntoSA/CXXExprEngine.cpp
rename to lib/StaticAnalyzer/CXXExprEngine.cpp
index 3ecd439d0ae52c141919ac5b757d327aaa1e4648..47b3a0bd06905f01f6c94b201cd24f4b7e9ee7cb 100644 (file)
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/AST/DeclCXX.h"
 
 using namespace clang;
similarity index 95%
rename from lib/EntoSA/Checker.cpp
rename to lib/StaticAnalyzer/Checker.cpp
index 943be6b93132d0bd66b52ada40cf9084002f19df..6867ff5b645ddbc99c689b4062c8423ca819ecf1 100644 (file)
@@ -12,7 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 using namespace clang;
 using namespace ento;
 
similarity index 97%
rename from lib/EntoSA/CheckerHelpers.cpp
rename to lib/StaticAnalyzer/CheckerHelpers.cpp
index 7c7f707afd6343497ab0a77fdce42b9df07d9313..be9fee548f255c546a05a77d1d8e013c44f5b12e 100644 (file)
@@ -11,7 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/CheckerHelpers.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
 #include "clang/AST/Expr.h"
 
 // Recursively find any substatements containing macros
similarity index 94%
rename from lib/EntoSA/Checkers/AdjustedReturnValueChecker.cpp
rename to lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
index 914b1e4fbbb4f12dd577a2b95f1e90c0b122761d..46e2de5c26d92a3ec05a19060fbdc57858180a46 100644 (file)
@@ -14,9 +14,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 97%
rename from lib/EntoSA/Checkers/AnalysisConsumer.cpp
rename to lib/StaticAnalyzer/Checkers/AnalysisConsumer.cpp
index 043a24a2ef6f3781f9b5003c825b71a8f674ae26..ee4eae2ebfa4a55c9a4b04c85f061bb5313033ad 100644 (file)
@@ -11,7 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/AnalysisConsumer.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/Analyses/UninitializedValues.h"
 #include "clang/Analysis/CFG.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
-#include "clang/EntoSA/ManagerRegistry.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
-#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
-#include "clang/EntoSA/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/ManagerRegistry.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
 
 // FIXME: Restructure checker registration.
 #include "ExprEngineExperimentalChecks.h"
similarity index 94%
rename from lib/EntoSA/Checkers/ArrayBoundChecker.cpp
rename to lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index c72a4668ab6842ce8f702dc2e6c92649c6fd58a4..13e628bcb1a56d32565a52e6c9bbc282eaedf4b8 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 98%
rename from lib/EntoSA/Checkers/ArrayBoundCheckerV2.cpp
rename to lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 33683bac32488fa67e119a8b5c6fc9d1aa578fdd..b55fadebf87402743963cc83c5c12c75caab31bc 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/AST/CharUnits.h"
 
 using namespace clang;
similarity index 97%
rename from lib/EntoSA/Checkers/AttrNonNullChecker.cpp
rename to lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index f887e24d1625fb1e28ad3f1f0d531a459ab1c7cc..646b30bc3153e5e68da8a8c2f7ebd15ff138e75d 100644 (file)
@@ -13,8 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 97%
rename from lib/EntoSA/Checkers/BasicObjCFoundationChecks.cpp
rename to lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 8e83160a2014aa54aba0e37cdce07c07b6569c06..b4e2959150f1ab536c36a871482288707926ee87 100644 (file)
 
 #include "BasicObjCFoundationChecks.h"
 
-#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
similarity index 97%
rename from lib/EntoSA/Checkers/BuiltinFunctionChecker.cpp
rename to lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 1db8aac93f87f65e17ee78d316fed64220cebb77..2e6f1b90e1114187ff7df4eb3dd4291ac8e6710b 100644 (file)
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 #include "clang/Basic/Builtins.h"
 
 using namespace clang;
similarity index 90%
rename from lib/EntoSA/Checkers/CMakeLists.txt
rename to lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 224a515d9aecc877b56ecfeb9df31b69b1a91e3a..e4b9541c2377ac80c0c7d8c1f7caa87a9ff8f4cb 100644 (file)
@@ -1,4 +1,4 @@
-add_clang_library(clangEntoCheckers
+add_clang_library(clangStaticAnalyzerCheckers
   AdjustedReturnValueChecker.cpp
   AnalysisConsumer.cpp
   ArrayBoundChecker.cpp
@@ -49,5 +49,5 @@ add_clang_library(clangEntoCheckers
   VLASizeChecker.cpp
   )
 
-add_dependencies(clangEntoCore ClangAttrClasses ClangAttrList ClangDeclNodes
+add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
                  ClangStmtNodes)
similarity index 99%
rename from lib/EntoSA/Checkers/CStringChecker.cpp
rename to lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 199d6b2f5e78e5701ce46977d63919ff257978be..b7513c39c13f6f41659c691c7639ba5dfe5bda8a 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineExperimentalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
 #include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
similarity index 99%
rename from lib/EntoSA/Checkers/CallAndMessageChecker.cpp
rename to lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 2fa37e3fa571ee9bc72460fd92dd025c8dcba69d..2998406da05910685997024a033a584179aba128 100644 (file)
@@ -15,8 +15,8 @@
 #include "ExprEngineInternalChecks.h"
 #include "clang/AST/ParentMap.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 95%
rename from lib/EntoSA/Checkers/CastSizeChecker.cpp
rename to lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 41a72ef32d335e2d4e17ed366dfdec1b7dfaf505..9329ea39d4598d3ac7bcabd87e531796838ac741 100644 (file)
@@ -12,8 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/AST/CharUnits.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 #include "ExprEngineInternalChecks.h"
 
 using namespace clang;
similarity index 95%
rename from lib/EntoSA/Checkers/CastToStructChecker.cpp
rename to lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index 83393b9268fba614fc95355e91c1fb9c7a9f3c74..dd6ac7ea84c037f1b43bc3cdec74442af57bd432 100644 (file)
@@ -13,8 +13,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 #include "ExprEngineInternalChecks.h"
 
 using namespace clang;
similarity index 98%
rename from lib/EntoSA/Checkers/CheckDeadStores.cpp
rename to lib/StaticAnalyzer/Checkers/CheckDeadStores.cpp
index 047c83abc64ad238bdf09fa94cf813824490b8c7..1fe40c56e833188f011f853393cb8a1e0ef7c814 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/AST/ASTContext.h"
similarity index 98%
rename from lib/EntoSA/Checkers/CheckObjCDealloc.cpp
rename to lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 391e30f61ebef1e4a69b8a0020ba375bca543071..932a6f5945f28af0b0b14438974d9f5a93cfdab6 100644 (file)
@@ -13,9 +13,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/DeclObjC.h"
similarity index 95%
rename from lib/EntoSA/Checkers/CheckObjCInstMethSignature.cpp
rename to lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index f908e69cc7d682ed3aef40b71d5740e7de71ad87..57e388f44dec7aae4648a598b248f015c08cac5e 100644 (file)
@@ -13,9 +13,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/ASTContext.h"
similarity index 99%
rename from lib/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp
rename to lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 98da69231c640d195106a3793be383fde35a9916..b30e985f38a55a1983baccb55350ae8b0482c692 100644 (file)
@@ -12,8 +12,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/TargetInfo.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 #include "clang/AST/StmtVisitor.h"
 #include "llvm/Support/raw_ostream.h"
 
similarity index 94%
rename from lib/EntoSA/Checkers/CheckSizeofPointer.cpp
rename to lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index f7ab9514e9bc5418b4ae5eb9aa79a02394077ac6..ed060b27fb45615817b79c5d76d8fad4b6fcc02b 100644 (file)
@@ -12,9 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "clang/AST/StmtVisitor.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 
 using namespace clang;
 using namespace ento;
similarity index 94%
rename from lib/EntoSA/Checkers/ChrootChecker.cpp
rename to lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index e951c29d1aee96d56f093b6d9c4bb733696b5058..a3f4daa3b05ce3b3ba0ab37517f350310867306b 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineExperimentalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/ImmutableMap.h"
 using namespace clang;
 using namespace ento;
similarity index 96%
rename from lib/EntoSA/Checkers/DereferenceChecker.cpp
rename to lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 35fae40935b4635838c518a7e16de84dabbbde4b..7dc8ec84dfe41edda79cd375dfff0379d9b153cf 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/Checkers/DereferenceChecker.h"
-#include "clang/EntoSA/PathSensitive/Checker.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 95%
rename from lib/EntoSA/Checkers/DivZeroChecker.cpp
rename to lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 24c743a8d051200cad5a88de0454b0d6b8af244a..8332af8f5d016a8e1a50e462ac6bf6c142280d3f 100644 (file)
@@ -13,8 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 99%
rename from lib/EntoSA/Checkers/ExprEngine.cpp
rename to lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index afd6318acc2f7d798d526dbab6fb5ce5032274b8..17bc339f7548e1c099d6c27ab6af0b6bcf6c3df0 100644 (file)
 // FIXME: Restructure checker registration.
 #include "ExprEngineInternalChecks.h"
 
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/PathSensitive/ExprEngineBuilders.h"
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/ParentMap.h"
 #include "clang/AST/StmtObjC.h"
similarity index 96%
rename from lib/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp
rename to lib/StaticAnalyzer/Checkers/ExprEngineExperimentalChecks.cpp
index 6ab5a4d5daf72120a26c2e721eb5447fa119e4c7..52a3aced2d0188b6c550323a8317ccb4edd10983 100644 (file)
@@ -14,7 +14,7 @@
 
 #include "ExprEngineInternalChecks.h"
 #include "ExprEngineExperimentalChecks.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
 
 using namespace clang;
 using namespace ento;
similarity index 94%
rename from lib/EntoSA/Checkers/FixedAddressChecker.cpp
rename to lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index ea736435d6be848f9c5fbed450fc0c95845f5527..77e9876d47905205ff3110af74025ad7f0897f26 100644 (file)
@@ -14,8 +14,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 88%
rename from lib/EntoSA/Checkers/FrontendActions.cpp
rename to lib/StaticAnalyzer/Checkers/FrontendActions.cpp
index b901afc5e14c8f22fd67c4f3a1fd324cae7d1e4d..b0e8e5d9bb1320eb1a6d93b9f702e8aee5618791 100644 (file)
@@ -7,9 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/FrontendActions.h"
+#include "clang/StaticAnalyzer/FrontendActions.h"
 #include "clang/Frontend/CompilerInstance.h"
-#include "clang/EntoSA/AnalysisConsumer.h"
+#include "clang/StaticAnalyzer/AnalysisConsumer.h"
 using namespace clang;
 using namespace ento;
 
similarity index 98%
rename from lib/EntoSA/Checkers/IdempotentOperationChecker.cpp
rename to lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 04f652cdcb9f34eeb387f88e00f655f3002ab120..435d3d4a48e5549305da1a335e52414313870b3f 100644 (file)
 #include "ExprEngineExperimentalChecks.h"
 #include "clang/Analysis/CFGStmtMap.h"
 #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerHelpers.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/CoreEngine.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
 #include "clang/AST/Stmt.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallSet.h"
similarity index 98%
rename from lib/EntoSA/Checkers/LLVMConventionsChecker.cpp
rename to lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index e88997f79ca76f4d64bc03db35990ea92684e2e6..eefad95f215f88480b36d2b4ce463c8c2cfa139a 100644 (file)
@@ -14,8 +14,8 @@
 
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/StmtVisitor.h"
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include <string>
 #include "llvm/ADT/StringRef.h"
 
similarity index 96%
rename from lib/EntoSA/Checkers/MacOSXAPIChecker.cpp
rename to lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index c2f5f4b83cfe0c3affb4e368966c2ea2da7076e7..44887fa76905f52109624719a5cf9493eb207104 100644 (file)
@@ -17,9 +17,9 @@
 
 #include "ExprEngineInternalChecks.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/raw_ostream.h"
similarity index 92%
rename from lib/EntoSA/Checkers/Makefile
rename to lib/StaticAnalyzer/Checkers/Makefile
index 9ba4e282d2cc82558e369596395ac9ec3b0d884c..d4de35c1f5836fc066b7e2f94d6a33762b4acb41 100644 (file)
@@ -12,6 +12,6 @@
 ##===----------------------------------------------------------------------===##
 
 CLANG_LEVEL := ../../..
-LIBRARYNAME := clangEntoCheckers
+LIBRARYNAME := clangStaticAnalyzerCheckers
 
 include $(CLANG_LEVEL)/Makefile
similarity index 98%
rename from lib/EntoSA/Checkers/MallocChecker.cpp
rename to lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 2b0ae82ccd7bc9a44adf18ffff9044d06ba93771..42243cb52511309ae28cac832a96cf2daebf9ee6 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineExperimentalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/ImmutableMap.h"
 using namespace clang;
 using namespace ento;
similarity index 93%
rename from lib/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp
rename to lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index acad46c35280620995eef13f133d4130725e4e1b..6ef242ba427a6b9c86762c4275f8185490e28a20 100644 (file)
@@ -15,9 +15,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 #include "BasicObjCFoundationChecks.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Decl.h"
similarity index 96%
rename from lib/EntoSA/Checkers/NSErrorChecker.cpp
rename to lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index d5c395f0a1112d0f8e22c66b0fd5c15541d900be..54e61188932e62fe82e38d05e1376065c5a886ab 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/Checkers/DereferenceChecker.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
 #include "BasicObjCFoundationChecks.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Decl.h"
similarity index 97%
rename from lib/EntoSA/Checkers/NoReturnFunctionChecker.cpp
rename to lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 4b96ddba3999e8e254245efe925fa91d0dd78603..8cdc04f9ff74fcd04c2ff71a2476d9cfd4d30d63 100644 (file)
@@ -13,7 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 #include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
similarity index 99%
rename from lib/EntoSA/Checkers/OSAtomicChecker.cpp
rename to lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
index cc67c3df7a53ecaecb14c92bb989161e84357a23..99317348421d4ec260cd2f17d039f73b8ecdedbc 100644 (file)
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 #include "clang/Basic/Builtins.h"
 
 using namespace clang;
similarity index 92%
rename from lib/EntoSA/Checkers/ObjCAtSyncChecker.cpp
rename to lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 3e901b60075d06ffacc628594223cf2fbf7af23d..2d94e8ce910f5c9c6763da69feeebc943006100f 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/Checkers/DereferenceChecker.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 96%
rename from lib/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp
rename to lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index a2e2475f2875964fbaeac7d8af81c874474009ad..799da332b95a8334b4ed6ef44cfbf9a58996910c 100644 (file)
@@ -13,9 +13,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/Checkers/LocalCheckers.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/DeclObjC.h"
similarity index 95%
rename from lib/EntoSA/Checkers/PointerArithChecker.cpp
rename to lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 30009a2560730fb7d2834b40e634e3829b3a5bef..2b03dbcd9c246b1172fa42e53163408844a3338f 100644 (file)
@@ -13,8 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 95%
rename from lib/EntoSA/Checkers/PointerSubChecker.cpp
rename to lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 923d0a86d8ec4f9a7794d5d6fe485387fd813125..1ba60f7541d2e704640dab816472e5e87968db1b 100644 (file)
@@ -14,8 +14,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 95%
rename from lib/EntoSA/Checkers/PthreadLockChecker.cpp
rename to lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 56c9adb50913cd27790c012009534fd34f57568e..7a91696c92cbaa1b5747a157823480583422cac7 100644 (file)
@@ -12,9 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
 #include "ExprEngineExperimentalChecks.h"
 #include "llvm/ADT/ImmutableSet.h"
 
similarity index 94%
rename from lib/EntoSA/Checkers/ReturnPointerRangeChecker.cpp
rename to lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 8afe9847aaa8d4332569b9c2f577e389c8cc2006..a56c1b65846e5a3206ea58d0c038632fcddf45c1 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 91%
rename from lib/EntoSA/Checkers/ReturnUndefChecker.cpp
rename to lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 8e46519b21b975c00198456d2cb639bd53ccc4fe..50ffd322db17e5937eff9d2809dccebf1e479362 100644 (file)
@@ -14,9 +14,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 97%
rename from lib/EntoSA/Checkers/StackAddrLeakChecker.cpp
rename to lib/StaticAnalyzer/Checkers/StackAddrLeakChecker.cpp
index c9aebadca12917dab2054b89a8cbe99b36e61a9d..1ec5c32aff03f92f5193f0f82742b717fc0a389d 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/SmallString.h"
 using namespace clang;
similarity index 97%
rename from lib/EntoSA/Checkers/StreamChecker.cpp
rename to lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index cb7899fbb223e011cc498415fb91077ffbddc449..a6d1e079c489d57864bf6e2f33873acae021fd05 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineExperimentalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/ImmutableMap.h"
 
 using namespace clang;
similarity index 97%
rename from lib/EntoSA/Checkers/UndefBranchChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 30d0728530163791fcf1b88e2f78404f36c910c8..c0b3b7afec727ce5ef22e1e19d8e6ac47ee344cf 100644 (file)
@@ -13,8 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 
 using namespace clang;
 using namespace ento;
similarity index 94%
rename from lib/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index dcdcf1f7412cd1d0c2fd711cb7ae3676c11c223e..57e698bb7c2d5e3baa5dad3d2f5beb96410b5163 100644 (file)
@@ -12,9 +12,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
similarity index 93%
rename from lib/EntoSA/Checkers/UndefResultChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index c0427402b17d450f70494f14a8afd161b2574597..91e489bd2a4086b05da6b4b8397e4fc7780d55d2 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 93%
rename from lib/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index aea78c048bea282473937b2f458d44325cf3ee62..2cd293b2f42eaaef934a9ba032d50b7583775b30 100644 (file)
@@ -13,8 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 95%
rename from lib/EntoSA/Checkers/UndefinedAssignmentChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 5060cdff9645571f699bef59afe913a81c257a7d..3146bbda41e3b78a03e105cedb7ab34e00cc80da 100644 (file)
@@ -13,8 +13,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExprEngineInternalChecks.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 
 using namespace clang;
 using namespace ento;
similarity index 98%
rename from lib/EntoSA/Checkers/UnixAPIChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index c45659c011202c45299dafcd43e1fb4d4d11c1c3..9092f93ba72c60e18cf7035f7eea92700e3546fd 100644 (file)
@@ -14,8 +14,8 @@
 
 #include "ExprEngineInternalChecks.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringSwitch.h"
 #include <fcntl.h>
similarity index 96%
rename from lib/EntoSA/Checkers/UnreachableCodeChecker.cpp
rename to lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index e3ea72e13373ecb5513f5dd3057346c5faedae56..98834485ebab5331d184144bba96557f5ee4250c 100644 (file)
 #include "clang/AST/ParentMap.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
-#include "clang/EntoSA/PathSensitive/CheckerHelpers.h"
-#include "clang/EntoSA/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
 #include "ExprEngineExperimentalChecks.h"
 #include "llvm/ADT/SmallPtrSet.h"
 
similarity index 96%
rename from lib/EntoSA/Checkers/VLASizeChecker.cpp
rename to lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 0d17238ee70324f2457b00f837b8bc50002569f4..e24521af536cf64d68e1cbc20fd9533c064a21d0 100644 (file)
@@ -16,9 +16,9 @@
 
 #include "ExprEngineInternalChecks.h"
 #include "clang/AST/CharUnits.h"
-#include "clang/EntoSA/BugReporter/BugType.h"
-#include "clang/EntoSA/PathSensitive/CheckerVisitor.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 
 using namespace clang;
 using namespace ento;
similarity index 99%
rename from lib/EntoSA/CoreEngine.cpp
rename to lib/StaticAnalyzer/CoreEngine.cpp
index 478e77b4af34bd8e2218ca018228ae14bdc56188..a23c7f9d2d4c411206d887122a9821677b3033f6 100644 (file)
@@ -12,9 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/AnalysisManager.h"
-#include "clang/EntoSA/PathSensitive/CoreEngine.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
 #include "clang/Index/TranslationUnit.h"
 #include "clang/AST/Expr.h"
 #include "llvm/Support/Casting.h"
diff --git a/lib/StaticAnalyzer/EntoSA/AggExprVisitor.cpp b/lib/StaticAnalyzer/EntoSA/AggExprVisitor.cpp
new file mode 100644 (file)
index 0000000..0cc2390
--- /dev/null
@@ -0,0 +1,63 @@
+//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- 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 AggExprVisitor class, which contains lots of boiler
+// plate code for evaluating expressions of C++ class type.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+/// AggExprVisitor is designed after AggExprEmitter of the CodeGen module.  It
+/// is used for evaluating exprs of C++ object type. Evaluating such exprs
+/// requires a destination pointer pointing to the object being evaluated
+/// into. Passing such a pointer around would pollute the Visit* interface of
+/// ExprEngine. AggExprVisitor encapsulates code that goes through various
+/// cast and construct exprs (and others), and at the final point, dispatches
+/// back to the ExprEngine to let the real evaluation logic happen.
+class AggExprVisitor : public StmtVisitor<AggExprVisitor> {
+  const MemRegion *Dest;
+  ExplodedNode *Pred;
+  ExplodedNodeSet &DstSet;
+  ExprEngine &Eng;
+
+public:
+  AggExprVisitor(const MemRegion *dest, ExplodedNode *N, ExplodedNodeSet &dst, 
+                 ExprEngine &eng)
+    : Dest(dest), Pred(N), DstSet(dst), Eng(eng) {}
+
+  void VisitCastExpr(CastExpr *E);
+  void VisitCXXConstructExpr(CXXConstructExpr *E);
+};
+}
+
+void AggExprVisitor::VisitCastExpr(CastExpr *E) {
+  switch (E->getCastKind()) {
+  default: 
+    assert(0 && "Unhandled cast kind");
+  case CK_NoOp:
+  case CK_ConstructorConversion:
+    Visit(E->getSubExpr());
+    break;
+  }
+}
+
+void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
+  Eng.VisitCXXConstructExpr(E, Dest, Pred, DstSet);
+}
+
+void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest, 
+                                ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+  AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E));
+}
diff --git a/lib/StaticAnalyzer/EntoSA/AnalysisManager.cpp b/lib/StaticAnalyzer/EntoSA/AnalysisManager.cpp
new file mode 100644 (file)
index 0000000..cc5e271
--- /dev/null
@@ -0,0 +1,32 @@
+//===-- AnalysisManager.cpp -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/Indexer.h"
+
+using namespace clang;
+using namespace ento;
+
+AnalysisContext *
+AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) {
+  idx::Entity Ent = idx::Entity::get(const_cast<Decl *>(D), 
+                                     Idxer->getProgram());
+  FunctionDecl *FuncDef;
+  idx::TranslationUnit *TU;
+  llvm::tie(FuncDef, TU) = Idxer->getDefinitionFor(Ent);
+
+  if (FuncDef == 0)
+    return 0;
+
+  // This AnalysisContext wraps function definition in another translation unit.
+  // But it is still owned by the AnalysisManager associated with the current
+  // translation unit.
+  return AnaCtxMgr.getContext(FuncDef, TU);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/EntoSA/AnalyzerStatsChecker.cpp
new file mode 100644 (file)
index 0000000..8521c18
--- /dev/null
@@ -0,0 +1,123 @@
+//==--AnalyzerStatsChecker.cpp - Analyzer visitation statistics --*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file reports various statistics about analyzer visitation.
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+
+// FIXME: Restructure checker registration.
+#include "Checkers/ExprEngineExperimentalChecks.h"
+
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> {
+public:
+  static void *getTag();
+  void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng);
+
+private:
+  llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
+};
+}
+
+void *AnalyzerStatsChecker::getTag() {
+  static int x = 0;
+  return &x;
+}
+
+void ento::RegisterAnalyzerStatsChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new AnalyzerStatsChecker());
+}
+
+void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G,
+                                            BugReporter &B,
+                                            ExprEngine &Eng) {
+  const CFG *C  = 0;
+  const Decl *D = 0;
+  const LocationContext *LC = 0;
+  const SourceManager &SM = B.getSourceManager();
+
+  // Iterate over explodedgraph
+  for (ExplodedGraph::node_iterator I = G.nodes_begin();
+      I != G.nodes_end(); ++I) {
+    const ProgramPoint &P = I->getLocation();
+    // Save the LocationContext if we don't have it already
+    if (!LC)
+      LC = P.getLocationContext();
+
+    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+      const CFGBlock *CB = BE->getBlock();
+      reachable.insert(CB);
+    }
+  }
+
+  // Get the CFG and the Decl of this block
+  C = LC->getCFG();
+  D = LC->getAnalysisContext()->getDecl();
+
+  unsigned total = 0, unreachable = 0;
+
+  // Find CFGBlocks that were not covered by any node
+  for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) {
+    const CFGBlock *CB = *I;
+    ++total;
+    // Check if the block is unreachable
+    if (!reachable.count(CB)) {
+      ++unreachable;
+    }
+  }
+
+  // We never 'reach' the entry block, so correct the unreachable count
+  unreachable--;
+
+  // Generate the warning string
+  llvm::SmallString<128> buf;
+  llvm::raw_svector_ostream output(buf);
+  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
+  if (Loc.isValid()) {
+    output << Loc.getFilename() << " : ";
+
+    if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+      const NamedDecl *ND = cast<NamedDecl>(D);
+      output << ND;
+    }
+    else if (isa<BlockDecl>(D)) {
+      output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
+    }
+  }
+  
+  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
+      << unreachable << " | Aborted Block: "
+      << (Eng.wasBlockAborted() ? "yes" : "no")
+      << " | Empty WorkList: "
+      << (Eng.hasEmptyWorkList() ? "yes" : "no");
+
+  B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
+      D->getLocation());
+
+  // Emit warning for each block we bailed out on
+  typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
+  const CoreEngine &CE = Eng.getCoreEngine();
+  for (AbortedIterator I = CE.blocks_aborted_begin(),
+      E = CE.blocks_aborted_end(); I != E; ++I) {
+    const BlockEdge &BE =  I->first;
+    const CFGBlock *Exit = BE.getDst();
+    const CFGElement &CE = Exit->front();
+    if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
+      B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
+          "stopped analyzing at this point", CS->getStmt()->getLocStart());
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/BasicConstraintManager.cpp b/lib/StaticAnalyzer/EntoSA/BasicConstraintManager.cpp
new file mode 100644 (file)
index 0000000..8bdc4fa
--- /dev/null
@@ -0,0 +1,338 @@
+//== BasicConstraintManager.cpp - Manage basic constraints.------*- 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 BasicConstraintManager, a class that tracks simple
+//  equality and inequality constraints on symbolic values of GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+
+namespace { class ConstNotEq {}; }
+namespace { class ConstEq {}; }
+
+typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
+typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
+
+static int ConstEqIndex = 0;
+static int ConstNotEqIndex = 0;
+
+namespace clang {
+namespace ento {
+template<>
+struct GRStateTrait<ConstNotEq> : public GRStatePartialTrait<ConstNotEqTy> {
+  static inline void* GDMIndex() { return &ConstNotEqIndex; }
+};
+
+template<>
+struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
+  static inline void* GDMIndex() { return &ConstEqIndex; }
+};
+}
+}
+
+namespace {
+// BasicConstraintManager only tracks equality and inequality constraints of
+// constants and integer variables.
+class BasicConstraintManager
+  : public SimpleConstraintManager {
+  GRState::IntSetTy::Factory ISetFactory;
+public:
+  BasicConstraintManager(GRStateManager &statemgr, SubEngine &subengine)
+    : SimpleConstraintManager(subengine), 
+      ISetFactory(statemgr.getAllocator()) {}
+
+  const GRState *assumeSymNE(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& V,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymEQ(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& V,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymLT(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& V,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymGT(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& V,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymGE(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& V,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymLE(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& V,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState* AddEQ(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
+
+  const GRState* AddNE(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
+
+  const llvm::APSInt* getSymVal(const GRState* state, SymbolRef sym) const;
+  bool isNotEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V)
+      const;
+  bool isEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V)
+      const;
+
+  const GRState* RemoveDeadBindings(const GRState* state, SymbolReaper& SymReaper);
+
+  void print(const GRState* state, llvm::raw_ostream& Out,
+             const char* nl, const char *sep);
+};
+
+} // end anonymous namespace
+
+ConstraintManager* ento::CreateBasicConstraintManager(GRStateManager& statemgr,
+                                                       SubEngine &subengine) {
+  return new BasicConstraintManager(statemgr, subengine);
+}
+
+
+const GRState*
+BasicConstraintManager::assumeSymNE(const GRState *state, SymbolRef sym,
+                                    const llvm::APSInt &V,
+                                    const llvm::APSInt &Adjustment) {
+  // First, determine if sym == X, where X+Adjustment != V.
+  llvm::APSInt Adjusted = V-Adjustment;
+  if (const llvm::APSInt* X = getSymVal(state, sym)) {
+    bool isFeasible = (*X != Adjusted);
+    return isFeasible ? state : NULL;
+  }
+
+  // Second, determine if sym+Adjustment != V.
+  if (isNotEqual(state, sym, Adjusted))
+    return state;
+
+  // If we reach here, sym is not a constant and we don't know if it is != V.
+  // Make that assumption.
+  return AddNE(state, sym, Adjusted);
+}
+
+const GRState*
+BasicConstraintManager::assumeSymEQ(const GRState *state, SymbolRef sym,
+                                    const llvm::APSInt &V,
+                                    const llvm::APSInt &Adjustment) {
+  // First, determine if sym == X, where X+Adjustment != V.
+  llvm::APSInt Adjusted = V-Adjustment;
+  if (const llvm::APSInt* X = getSymVal(state, sym)) {
+    bool isFeasible = (*X == Adjusted);
+    return isFeasible ? state : NULL;
+  }
+
+  // Second, determine if sym+Adjustment != V.
+  if (isNotEqual(state, sym, Adjusted))
+    return NULL;
+
+  // If we reach here, sym is not a constant and we don't know if it is == V.
+  // Make that assumption.
+  return AddEQ(state, sym, Adjusted);
+}
+
+// The logic for these will be handled in another ConstraintManager.
+const GRState*
+BasicConstraintManager::assumeSymLT(const GRState *state, SymbolRef sym,
+                                    const llvm::APSInt &V,
+                                    const llvm::APSInt &Adjustment) {
+  // Is 'V' the smallest possible value?
+  if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
+    // sym cannot be any value less than 'V'.  This path is infeasible.
+    return NULL;
+  }
+
+  // FIXME: For now have assuming x < y be the same as assuming sym != V;
+  return assumeSymNE(state, sym, V, Adjustment);
+}
+
+const GRState*
+BasicConstraintManager::assumeSymGT(const GRState *state, SymbolRef sym,
+                                    const llvm::APSInt &V,
+                                    const llvm::APSInt &Adjustment) {
+  // Is 'V' the largest possible value?
+  if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
+    // sym cannot be any value greater than 'V'.  This path is infeasible.
+    return NULL;
+  }
+
+  // FIXME: For now have assuming x > y be the same as assuming sym != V;
+  return assumeSymNE(state, sym, V, Adjustment);
+}
+
+const GRState*
+BasicConstraintManager::assumeSymGE(const GRState *state, SymbolRef sym,
+                                    const llvm::APSInt &V,
+                                    const llvm::APSInt &Adjustment) {
+  // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
+  if (const llvm::APSInt *X = getSymVal(state, sym)) {
+    bool isFeasible = (*X >= V-Adjustment);
+    return isFeasible ? state : NULL;
+  }
+
+  // Sym is not a constant, but it is worth looking to see if V is the
+  // maximum integer value.
+  if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
+    llvm::APSInt Adjusted = V-Adjustment;
+
+    // If we know that sym != V (after adjustment), then this condition
+    // is infeasible since there is no other value greater than V.
+    bool isFeasible = !isNotEqual(state, sym, Adjusted);
+
+    // If the path is still feasible then as a consequence we know that
+    // 'sym+Adjustment == V' because there are no larger values.
+    // Add this constraint.
+    return isFeasible ? AddEQ(state, sym, Adjusted) : NULL;
+  }
+
+  return state;
+}
+
+const GRState*
+BasicConstraintManager::assumeSymLE(const GRState *state, SymbolRef sym,
+                                    const llvm::APSInt &V,
+                                    const llvm::APSInt &Adjustment) {
+  // Reject a path if the value of sym is a constant X and !(X+Adj <= V).
+  if (const llvm::APSInt* X = getSymVal(state, sym)) {
+    bool isFeasible = (*X <= V-Adjustment);
+    return isFeasible ? state : NULL;
+  }
+
+  // Sym is not a constant, but it is worth looking to see if V is the
+  // minimum integer value.
+  if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
+    llvm::APSInt Adjusted = V-Adjustment;
+
+    // If we know that sym != V (after adjustment), then this condition
+    // is infeasible since there is no other value less than V.
+    bool isFeasible = !isNotEqual(state, sym, Adjusted);
+
+    // If the path is still feasible then as a consequence we know that
+    // 'sym+Adjustment == V' because there are no smaller values.
+    // Add this constraint.
+    return isFeasible ? AddEQ(state, sym, Adjusted) : NULL;
+  }
+
+  return state;
+}
+
+const GRState* BasicConstraintManager::AddEQ(const GRState* state, SymbolRef sym,
+                                             const llvm::APSInt& V) {
+  // Create a new state with the old binding replaced.
+  return state->set<ConstEq>(sym, &state->getBasicVals().getValue(V));
+}
+
+const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym,
+                                             const llvm::APSInt& V) {
+
+  // First, retrieve the NE-set associated with the given symbol.
+  ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
+  GRState::IntSetTy S = T ? *T : ISetFactory.getEmptySet();
+
+  // Now add V to the NE set.
+  S = ISetFactory.add(S, &state->getBasicVals().getValue(V));
+
+  // Create a new state with the old binding replaced.
+  return state->set<ConstNotEq>(sym, S);
+}
+
+const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* state,
+                                                      SymbolRef sym) const {
+  const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
+  return T ? *T : NULL;
+}
+
+bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym,
+                                        const llvm::APSInt& V) const {
+
+  // Retrieve the NE-set associated with the given symbol.
+  const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
+
+  // See if V is present in the NE-set.
+  return T ? T->contains(&state->getBasicVals().getValue(V)) : false;
+}
+
+bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym,
+                                     const llvm::APSInt& V) const {
+  // Retrieve the EQ-set associated with the given symbol.
+  const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
+  // See if V is present in the EQ-set.
+  return T ? **T == V : false;
+}
+
+/// Scan all symbols referenced by the constraints. If the symbol is not alive
+/// as marked in LSymbols, mark it as dead in DSymbols.
+const GRState*
+BasicConstraintManager::RemoveDeadBindings(const GRState* state,
+                                           SymbolReaper& SymReaper) {
+
+  ConstEqTy CE = state->get<ConstEq>();
+  ConstEqTy::Factory& CEFactory = state->get_context<ConstEq>();
+
+  for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
+    SymbolRef sym = I.getKey();
+    if (SymReaper.maybeDead(sym))
+      CE = CEFactory.remove(CE, sym);
+  }
+  state = state->set<ConstEq>(CE);
+
+  ConstNotEqTy CNE = state->get<ConstNotEq>();
+  ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>();
+
+  for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
+    SymbolRef sym = I.getKey();
+    if (SymReaper.maybeDead(sym))
+      CNE = CNEFactory.remove(CNE, sym);
+  }
+
+  return state->set<ConstNotEq>(CNE);
+}
+
+void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
+                                   const char* nl, const char *sep) {
+  // Print equality constraints.
+
+  ConstEqTy CE = state->get<ConstEq>();
+
+  if (!CE.isEmpty()) {
+    Out << nl << sep << "'==' constraints:";
+    for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
+      Out << nl << " $" << I.getKey() << " : " << *I.getData();
+  }
+
+  // Print != constraints.
+
+  ConstNotEqTy CNE = state->get<ConstNotEq>();
+
+  if (!CNE.isEmpty()) {
+    Out << nl << sep << "'!=' constraints:";
+
+    for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
+      Out << nl << " $" << I.getKey() << " : ";
+      bool isFirst = true;
+
+      GRState::IntSetTy::iterator J = I.getData().begin(),
+                                  EJ = I.getData().end();
+
+      for ( ; J != EJ; ++J) {
+        if (isFirst) isFirst = false;
+        else Out << ", ";
+
+        Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream.
+      }
+    }
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/BasicStore.cpp b/lib/StaticAnalyzer/EntoSA/BasicStore.cpp
new file mode 100644 (file)
index 0000000..35bcf94
--- /dev/null
@@ -0,0 +1,594 @@
+//== BasicStore.cpp - Basic map from Locations to 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 defined the BasicStore and BasicStoreManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+using namespace clang;
+using namespace ento;
+
+typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
+
+namespace {
+
+class BasicStoreSubRegionMap : public SubRegionMap {
+public:
+  BasicStoreSubRegionMap() {}
+
+  bool iterSubRegions(const MemRegion* R, Visitor& V) const {
+    return true; // Do nothing.  No subregions.
+  }
+};
+
+class BasicStoreManager : public StoreManager {
+  BindingsTy::Factory VBFactory;
+public:
+  BasicStoreManager(GRStateManager& mgr)
+    : StoreManager(mgr), VBFactory(mgr.getAllocator()) {}
+
+  ~BasicStoreManager() {}
+
+  SubRegionMap *getSubRegionMap(Store store) {
+    return new BasicStoreSubRegionMap();
+  }
+
+  SVal Retrieve(Store store, Loc loc, QualType T = QualType());
+
+  Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+                         unsigned Count, InvalidatedSymbols *IS);
+
+  Store InvalidateRegions(Store store, const MemRegion * const *Begin,
+                          const MemRegion * const *End, const Expr *E,
+                          unsigned Count, InvalidatedSymbols *IS,
+                          bool invalidateGlobals, InvalidatedRegions *Regions);
+
+  Store scanForIvars(Stmt *B, const Decl* SelfDecl,
+                     const MemRegion *SelfRegion, Store St);
+
+  Store Bind(Store St, Loc loc, SVal V);
+  Store Remove(Store St, Loc loc);
+  Store getInitialStore(const LocationContext *InitLoc);
+
+  Store BindCompoundLiteral(Store store, const CompoundLiteralExpr*,
+                            const LocationContext*, SVal val) {
+    return store;
+  }
+
+  /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
+  ///  conversions between arrays and pointers.
+  SVal ArrayToPointer(Loc Array) { return Array; }
+
+  /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values.
+  ///  It updatees the GRState object in place with the values removed.
+  Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx,
+                           SymbolReaper& SymReaper,
+                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+
+  void iterBindings(Store store, BindingsHandler& f);
+
+  Store BindDecl(Store store, const VarRegion *VR, SVal InitVal) {
+    return BindDeclInternal(store, VR, &InitVal);
+  }
+
+  Store BindDeclWithNoInit(Store store, const VarRegion *VR) {
+    return BindDeclInternal(store, VR, 0);
+  }
+
+  Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal);
+
+  static inline BindingsTy GetBindings(Store store) {
+    return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
+  }
+
+  void print(Store store, llvm::raw_ostream& Out, const char* nl,
+             const char *sep);
+
+private:
+  SVal LazyRetrieve(Store store, const TypedRegion *R);
+};
+
+} // end anonymous namespace
+
+
+StoreManager* ento::CreateBasicStoreManager(GRStateManager& StMgr) {
+  return new BasicStoreManager(StMgr);
+}
+
+static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
+  bool foundPointer = false;
+  while (1) {
+    const PointerType *PT = T->getAs<PointerType>();
+    if (!PT) {
+      if (!foundPointer)
+        return false;
+
+      // intptr_t* or intptr_t**, etc?
+      if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy))
+        return true;
+
+      QualType X = C.getCanonicalType(T).getUnqualifiedType();
+      return X == C.VoidTy;
+    }
+
+    foundPointer = true;
+    T = PT->getPointeeType();
+  }
+}
+
+SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) {
+  const VarRegion *VR = dyn_cast<VarRegion>(R);
+  if (!VR)
+    return UnknownVal();
+
+  const VarDecl *VD = VR->getDecl();
+  QualType T = VD->getType();
+
+  // Only handle simple types that we can symbolicate.
+  if (!SymbolManager::canSymbolicate(T) || !T->isScalarType())
+    return UnknownVal();
+
+  // Globals and parameters start with symbolic values.
+  // Local variables initially are undefined.
+
+  // Non-static globals may have had their values reset by InvalidateRegions.
+  const MemSpaceRegion *MS = VR->getMemorySpace();
+  if (isa<NonStaticGlobalSpaceRegion>(MS)) {
+    BindingsTy B = GetBindings(store);
+    // FIXME: Copy-and-pasted from RegionStore.cpp.
+    if (BindingsTy::data_type *Val = B.lookup(MS)) {
+      if (SymbolRef parentSym = Val->getAsSymbol())
+        return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
+
+      if (Val->isZeroConstant())
+        return svalBuilder.makeZeroVal(T);
+
+      if (Val->isUnknownOrUndef())
+        return *Val;
+
+      assert(0 && "Unknown default value.");
+    }
+  }
+
+  if (VR->hasGlobalsOrParametersStorage() ||
+      isa<UnknownSpaceRegion>(VR->getMemorySpace()))
+    return svalBuilder.getRegionValueSymbolVal(R);
+
+  return UndefinedVal();
+}
+
+SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
+  if (isa<UnknownVal>(loc))
+    return UnknownVal();
+
+  assert(!isa<UndefinedVal>(loc));
+
+  switch (loc.getSubKind()) {
+
+    case loc::MemRegionKind: {
+      const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
+
+      if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) ||
+          isa<CXXThisRegion>(R)))
+        return UnknownVal();
+
+      BindingsTy B = GetBindings(store);
+      BindingsTy::data_type *Val = B.lookup(R);
+      const TypedRegion *TR = cast<TypedRegion>(R);
+
+      if (Val)
+        return CastRetrievedVal(*Val, TR, T);
+
+      SVal V = LazyRetrieve(store, TR);
+      return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
+    }
+
+    case loc::ConcreteIntKind:
+      // Support direct accesses to memory.  It's up to individual checkers
+      // to flag an error.
+      return UnknownVal();
+
+    default:
+      assert (false && "Invalid Loc.");
+      break;
+  }
+
+  return UnknownVal();
+}
+
+Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) {
+  if (isa<loc::ConcreteInt>(loc))
+    return store;
+
+  const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
+
+  // Special case: a default symbol assigned to the NonStaticGlobalsSpaceRegion
+  //  that is used to derive other symbols.
+  if (isa<NonStaticGlobalSpaceRegion>(R)) {
+    BindingsTy B = GetBindings(store);
+    return VBFactory.add(B, R, V).getRoot();
+  }
+
+  // Special case: handle store of pointer values (Loc) to pointers via
+  // a cast to intXX_t*, void*, etc.  This is needed to handle
+  // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier.
+  if (isa<Loc>(V) || isa<nonloc::LocAsInteger>(V))
+    if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+      // FIXME: Should check for index 0.
+      QualType T = ER->getLocationType();
+
+      if (isHigherOrderRawPtr(T, Ctx))
+        R = ER->getSuperRegion();
+    }
+
+  if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) || isa<CXXThisRegion>(R)))
+    return store;
+
+  const TypedRegion *TyR = cast<TypedRegion>(R);
+
+  // Do not bind to arrays.  We need to explicitly check for this so that
+  // we do not encounter any weirdness of trying to load/store from arrays.
+  if (TyR->isBoundable() && TyR->getValueType()->isArrayType())
+    return store;
+
+  if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&V)) {
+    // Only convert 'V' to a location iff the underlying region type
+    // is a location as well.
+    // FIXME: We are allowing a store of an arbitrary location to
+    // a pointer.  We may wish to flag a type error here if the types
+    // are incompatible.  This may also cause lots of breakage
+    // elsewhere. Food for thought.
+    if (TyR->isBoundable() && Loc::IsLocType(TyR->getValueType()))
+      V = X->getLoc();
+  }
+
+  BindingsTy B = GetBindings(store);
+  return V.isUnknown()
+    ? VBFactory.remove(B, R).getRoot()
+    : VBFactory.add(B, R, V).getRoot();
+}
+
+Store BasicStoreManager::Remove(Store store, Loc loc) {
+  switch (loc.getSubKind()) {
+    case loc::MemRegionKind: {
+      const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
+
+      if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) ||
+          isa<CXXThisRegion>(R)))
+        return store;
+
+      return VBFactory.remove(GetBindings(store), R).getRoot();
+    }
+    default:
+      assert ("Remove for given Loc type not yet implemented.");
+      return store;
+  }
+}
+
+Store BasicStoreManager::RemoveDeadBindings(Store store,
+                                            const StackFrameContext *LCtx,
+                                            SymbolReaper& SymReaper,
+                           llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+  BindingsTy B = GetBindings(store);
+  typedef SVal::symbol_iterator symbol_iterator;
+
+  // Iterate over the variable bindings.
+  for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
+    if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) {
+      if (SymReaper.isLive(VR))
+        RegionRoots.push_back(VR);
+      else
+        continue;
+    }
+    else if (isa<ObjCIvarRegion>(I.getKey()) ||
+             isa<NonStaticGlobalSpaceRegion>(I.getKey()) ||
+             isa<CXXThisRegion>(I.getKey()))
+      RegionRoots.push_back(I.getKey());
+    else
+      continue;
+
+    // Mark the bindings in the data as live.
+    SVal X = I.getData();
+    for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
+      SymReaper.markLive(*SI);
+  }
+
+  // Scan for live variables and live symbols.
+  llvm::SmallPtrSet<const MemRegion*, 10> Marked;
+
+  while (!RegionRoots.empty()) {
+    const MemRegion* MR = RegionRoots.back();
+    RegionRoots.pop_back();
+
+    while (MR) {
+      if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) {
+        SymReaper.markLive(SymR->getSymbol());
+        break;
+      }
+      else if (isa<VarRegion>(MR) || isa<ObjCIvarRegion>(MR) ||
+               isa<NonStaticGlobalSpaceRegion>(MR) || isa<CXXThisRegion>(MR)) {
+        if (Marked.count(MR))
+          break;
+
+        Marked.insert(MR);
+        SVal X = Retrieve(store, loc::MemRegionVal(MR));
+
+        // FIXME: We need to handle symbols nested in region definitions.
+        for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end();SI!=SE;++SI)
+          SymReaper.markLive(*SI);
+
+        if (!isa<loc::MemRegionVal>(X))
+          break;
+
+        const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X);
+        RegionRoots.push_back(LVD.getRegion());
+        break;
+      }
+      else if (const SubRegion* R = dyn_cast<SubRegion>(MR))
+        MR = R->getSuperRegion();
+      else
+        break;
+    }
+  }
+
+  // Remove dead variable bindings.
+  for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
+    const MemRegion* R = I.getKey();
+
+    if (!Marked.count(R)) {
+      store = Remove(store, svalBuilder.makeLoc(R));
+      SVal X = I.getData();
+
+      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
+        SymReaper.maybeDead(*SI);
+    }
+  }
+
+  return store;
+}
+
+Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl,
+                                      const MemRegion *SelfRegion, Store St) {
+  for (Stmt::child_iterator CI=B->child_begin(), CE=B->child_end();
+       CI != CE; ++CI) {
+
+    if (!*CI)
+      continue;
+
+    // Check if the statement is an ivar reference.  We only
+    // care about self.ivar.
+    if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(*CI)) {
+      const Expr *Base = IV->getBase()->IgnoreParenCasts();
+      if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Base)) {
+        if (DR->getDecl() == SelfDecl) {
+          const ObjCIvarRegion *IVR = MRMgr.getObjCIvarRegion(IV->getDecl(),
+                                                         SelfRegion);
+          SVal X = svalBuilder.getRegionValueSymbolVal(IVR);
+          St = Bind(St, svalBuilder.makeLoc(IVR), X);
+        }
+      }
+    }
+    else
+      St = scanForIvars(*CI, SelfDecl, SelfRegion, St);
+  }
+
+  return St;
+}
+
+Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
+  // The LiveVariables information already has a compilation of all VarDecls
+  // used in the function.  Iterate through this set, and "symbolicate"
+  // any VarDecl whose value originally comes from outside the function.
+  typedef LiveVariables::AnalysisDataTy LVDataTy;
+  LVDataTy& D = InitLoc->getLiveVariables()->getAnalysisData();
+  Store St = VBFactory.getEmptyMap().getRoot();
+
+  for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
+    const NamedDecl* ND = I->first;
+
+    // Handle implicit parameters.
+    if (const ImplicitParamDecl* PD = dyn_cast<ImplicitParamDecl>(ND)) {
+      const Decl& CD = *InitLoc->getDecl();
+      if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) {
+        if (MD->getSelfDecl() == PD) {
+          // FIXME: Add type constraints (when they become available) to
+          // SelfRegion?  (i.e., it implements MD->getClassInterface()).
+          const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
+          const MemRegion *SelfRegion =
+            svalBuilder.getRegionValueSymbolVal(VR).getAsRegion();
+          assert(SelfRegion);
+          St = Bind(St, svalBuilder.makeLoc(VR), loc::MemRegionVal(SelfRegion));
+          // Scan the method for ivar references.  While this requires an
+          // entire AST scan, the cost should not be high in practice.
+          St = scanForIvars(MD->getBody(), PD, SelfRegion, St);
+        }
+      }
+    }
+  }
+
+  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(InitLoc->getDecl())) {
+    // For C++ methods add symbolic region for 'this' in initial stack frame.
+    QualType ThisT = MD->getThisType(StateMgr.getContext());
+    MemRegionManager &RegMgr = svalBuilder.getRegionManager();
+    const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc);
+    SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR);
+    St = Bind(St, svalBuilder.makeLoc(ThisR), ThisV);
+  }
+
+  return St;
+}
+
+Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
+                                          SVal* InitVal) {
+
+  BasicValueFactory& BasicVals = StateMgr.getBasicVals();
+  const VarDecl *VD = VR->getDecl();
+
+  // BasicStore does not model arrays and structs.
+  if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType())
+    return store;
+
+  if (VD->hasGlobalStorage()) {
+    // Handle variables with global storage: extern, static, PrivateExtern.
+
+    // FIXME:: static variables may have an initializer, but the second time a
+    // function is called those values may not be current. Currently, a function
+    // will not be called more than once.
+
+    // Static global variables should not be visited here.
+    assert(!(VD->getStorageClass() == SC_Static &&
+             VD->isFileVarDecl()));
+
+    // Process static variables.
+    if (VD->getStorageClass() == SC_Static) {
+      // C99: 6.7.8 Initialization
+      //  If an object that has static storage duration is not initialized
+      //  explicitly, then:
+      //   â€”if it has pointer type, it is initialized to a null pointer;
+      //   â€”if it has arithmetic type, it is initialized to (positive or
+      //     unsigned) zero;
+      if (!InitVal) {
+        QualType T = VD->getType();
+        if (Loc::IsLocType(T))
+          store = Bind(store, loc::MemRegionVal(VR),
+                       loc::ConcreteInt(BasicVals.getValue(0, T)));
+        else if (T->isIntegerType() && T->isScalarType())
+          store = Bind(store, loc::MemRegionVal(VR),
+                       nonloc::ConcreteInt(BasicVals.getValue(0, T)));
+      } else {
+        store = Bind(store, loc::MemRegionVal(VR), *InitVal);
+      }
+    }
+  } else {
+    // Process local scalar variables.
+    QualType T = VD->getType();
+    // BasicStore only supports scalars.
+    if ((T->isScalarType() || T->isReferenceType()) &&
+        svalBuilder.getSymbolManager().canSymbolicate(T)) {
+      SVal V = InitVal ? *InitVal : UndefinedVal();
+      store = Bind(store, loc::MemRegionVal(VR), V);
+    }
+  }
+
+  return store;
+}
+
+void BasicStoreManager::print(Store store, llvm::raw_ostream& Out,
+                              const char* nl, const char *sep) {
+
+  BindingsTy B = GetBindings(store);
+  Out << "Variables:" << nl;
+
+  bool isFirst = true;
+
+  for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
+    if (isFirst)
+      isFirst = false;
+    else
+      Out << nl;
+
+    Out << ' ' << I.getKey() << " : " << I.getData();
+  }
+}
+
+
+void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
+  BindingsTy B = GetBindings(store);
+
+  for (BindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I)
+    if (!f.HandleBinding(*this, store, I.getKey(), I.getData()))
+      return;
+
+}
+
+StoreManager::BindingsHandler::~BindingsHandler() {}
+
+//===----------------------------------------------------------------------===//
+// Binding invalidation.
+//===----------------------------------------------------------------------===//
+
+
+Store BasicStoreManager::InvalidateRegions(Store store,
+                                           const MemRegion * const *I,
+                                           const MemRegion * const *End,
+                                           const Expr *E, unsigned Count,
+                                           InvalidatedSymbols *IS,
+                                           bool invalidateGlobals,
+                                           InvalidatedRegions *Regions) {
+  if (invalidateGlobals) {
+    BindingsTy B = GetBindings(store);
+    for (BindingsTy::iterator I=B.begin(), End=B.end(); I != End; ++I) {
+      const MemRegion *R = I.getKey();
+      if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()))
+        store = InvalidateRegion(store, R, E, Count, IS);
+    }
+  }
+
+  for ( ; I != End ; ++I) {
+    const MemRegion *R = *I;
+    // Don't invalidate globals twice.
+    if (invalidateGlobals) {
+      if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()))
+        continue;
+    }
+    store = InvalidateRegion(store, *I, E, Count, IS);
+    if (Regions)
+      Regions->push_back(R);
+  }
+
+  // FIXME: This is copy-and-paste from RegionStore.cpp.
+  if (invalidateGlobals) {
+    // Bind the non-static globals memory space to a new symbol that we will
+    // use to derive the bindings for all non-static globals.
+    const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion();
+    SVal V =
+      svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, E,
+                                  /* symbol type, doesn't matter */ Ctx.IntTy,
+                                  Count);
+
+    store = Bind(store, loc::MemRegionVal(GS), V);
+    if (Regions)
+      Regions->push_back(GS);
+  }
+
+  return store;
+}
+
+
+Store BasicStoreManager::InvalidateRegion(Store store,
+                                          const MemRegion *R,
+                                          const Expr *E,
+                                          unsigned Count,
+                                          InvalidatedSymbols *IS) {
+  R = R->StripCasts();
+
+  if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
+      return store;
+
+  if (IS) {
+    BindingsTy B = GetBindings(store);
+    if (BindingsTy::data_type *Val = B.lookup(R)) {
+      if (SymbolRef Sym = Val->getAsSymbol())
+        IS->insert(Sym);
+    }
+  }
+
+  QualType T = cast<TypedRegion>(R)->getValueType();
+  SVal V = svalBuilder.getConjuredSymbolVal(R, E, T, Count);
+  return Bind(store, loc::MemRegionVal(R), V);
+}
+
diff --git a/lib/StaticAnalyzer/EntoSA/BasicValueFactory.cpp b/lib/StaticAnalyzer/EntoSA/BasicValueFactory.cpp
new file mode 100644 (file)
index 0000000..d8b501b
--- /dev/null
@@ -0,0 +1,290 @@
+//=== BasicValueFactory.cpp - Basic values for Path Sens analysis --*- 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 BasicValueFactory, a class that manages the lifetime
+//  of APSInt objects and symbolic constraints used by ExprEngine
+//  and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
+
+using namespace clang;
+using namespace ento;
+
+void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T,
+                              llvm::ImmutableList<SVal> L) {
+  T.Profile(ID);
+  ID.AddPointer(L.getInternalPointer());
+}
+
+void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID,
+                                  const void *store,const TypedRegion *region) {
+  ID.AddPointer(store);
+  ID.AddPointer(region);
+}
+
+typedef std::pair<SVal, uintptr_t> SValData;
+typedef std::pair<SVal, SVal> SValPair;
+
+namespace llvm {
+template<> struct FoldingSetTrait<SValData> {
+  static inline void Profile(const SValData& X, llvm::FoldingSetNodeID& ID) {
+    X.first.Profile(ID);
+    ID.AddPointer( (void*) X.second);
+  }
+};
+
+template<> struct FoldingSetTrait<SValPair> {
+  static inline void Profile(const SValPair& X, llvm::FoldingSetNodeID& ID) {
+    X.first.Profile(ID);
+    X.second.Profile(ID);
+  }
+};
+}
+
+typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValData> >
+  PersistentSValsTy;
+
+typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<SValPair> >
+  PersistentSValPairsTy;
+
+BasicValueFactory::~BasicValueFactory() {
+  // Note that the dstor for the contents of APSIntSet will never be called,
+  // so we iterate over the set and invoke the dstor for each APSInt.  This
+  // frees an aux. memory allocated to represent very large constants.
+  for (APSIntSetTy::iterator I=APSIntSet.begin(), E=APSIntSet.end(); I!=E; ++I)
+    I->getValue().~APSInt();
+
+  delete (PersistentSValsTy*) PersistentSVals;
+  delete (PersistentSValPairsTy*) PersistentSValPairs;
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(const llvm::APSInt& X) {
+  llvm::FoldingSetNodeID ID;
+  void* InsertPos;
+  typedef llvm::FoldingSetNodeWrapper<llvm::APSInt> FoldNodeTy;
+
+  X.Profile(ID);
+  FoldNodeTy* P = APSIntSet.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!P) {
+    P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
+    new (P) FoldNodeTy(X);
+    APSIntSet.InsertNode(P, InsertPos);
+  }
+
+  return *P;
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(const llvm::APInt& X,
+                                                bool isUnsigned) {
+  llvm::APSInt V(X, isUnsigned);
+  return getValue(V);
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
+                                           bool isUnsigned) {
+  llvm::APSInt V(BitWidth, isUnsigned);
+  V = X;
+  return getValue(V);
+}
+
+const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) {
+
+  unsigned bits = Ctx.getTypeSize(T);
+  llvm::APSInt V(bits, T->isUnsignedIntegerType() || Loc::IsLocType(T));
+  V = X;
+  return getValue(V);
+}
+
+const CompoundValData*
+BasicValueFactory::getCompoundValData(QualType T,
+                                      llvm::ImmutableList<SVal> Vals) {
+
+  llvm::FoldingSetNodeID ID;
+  CompoundValData::Profile(ID, T, Vals);
+  void* InsertPos;
+
+  CompoundValData* D = CompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!D) {
+    D = (CompoundValData*) BPAlloc.Allocate<CompoundValData>();
+    new (D) CompoundValData(T, Vals);
+    CompoundValDataSet.InsertNode(D, InsertPos);
+  }
+
+  return D;
+}
+
+const LazyCompoundValData*
+BasicValueFactory::getLazyCompoundValData(const void *store,
+                                          const TypedRegion *region) {
+  llvm::FoldingSetNodeID ID;
+  LazyCompoundValData::Profile(ID, store, region);
+  void* InsertPos;
+
+  LazyCompoundValData *D =
+    LazyCompoundValDataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!D) {
+    D = (LazyCompoundValData*) BPAlloc.Allocate<LazyCompoundValData>();
+    new (D) LazyCompoundValData(store, region);
+    LazyCompoundValDataSet.InsertNode(D, InsertPos);
+  }
+
+  return D;
+}
+
+const llvm::APSInt*
+BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
+                             const llvm::APSInt& V1, const llvm::APSInt& V2) {
+
+  switch (Op) {
+    default:
+      assert (false && "Invalid Opcode.");
+
+    case BO_Mul:
+      return &getValue( V1 * V2 );
+
+    case BO_Div:
+      return &getValue( V1 / V2 );
+
+    case BO_Rem:
+      return &getValue( V1 % V2 );
+
+    case BO_Add:
+      return &getValue( V1 + V2 );
+
+    case BO_Sub:
+      return &getValue( V1 - V2 );
+
+    case BO_Shl: {
+
+      // FIXME: This logic should probably go higher up, where we can
+      // test these conditions symbolically.
+
+      // FIXME: Expand these checks to include all undefined behavior.
+
+      if (V2.isSigned() && V2.isNegative())
+        return NULL;
+
+      uint64_t Amt = V2.getZExtValue();
+
+      if (Amt > V1.getBitWidth())
+        return NULL;
+
+      return &getValue( V1.operator<<( (unsigned) Amt ));
+    }
+
+    case BO_Shr: {
+
+      // FIXME: This logic should probably go higher up, where we can
+      // test these conditions symbolically.
+
+      // FIXME: Expand these checks to include all undefined behavior.
+
+      if (V2.isSigned() && V2.isNegative())
+        return NULL;
+
+      uint64_t Amt = V2.getZExtValue();
+
+      if (Amt > V1.getBitWidth())
+        return NULL;
+
+      return &getValue( V1.operator>>( (unsigned) Amt ));
+    }
+
+    case BO_LT:
+      return &getTruthValue( V1 < V2 );
+
+    case BO_GT:
+      return &getTruthValue( V1 > V2 );
+
+    case BO_LE:
+      return &getTruthValue( V1 <= V2 );
+
+    case BO_GE:
+      return &getTruthValue( V1 >= V2 );
+
+    case BO_EQ:
+      return &getTruthValue( V1 == V2 );
+
+    case BO_NE:
+      return &getTruthValue( V1 != V2 );
+
+      // Note: LAnd, LOr, Comma are handled specially by higher-level logic.
+
+    case BO_And:
+      return &getValue( V1 & V2 );
+
+    case BO_Or:
+      return &getValue( V1 | V2 );
+
+    case BO_Xor:
+      return &getValue( V1 ^ V2 );
+  }
+}
+
+
+const std::pair<SVal, uintptr_t>&
+BasicValueFactory::getPersistentSValWithData(const SVal& V, uintptr_t Data) {
+
+  // Lazily create the folding set.
+  if (!PersistentSVals) PersistentSVals = new PersistentSValsTy();
+
+  llvm::FoldingSetNodeID ID;
+  void* InsertPos;
+  V.Profile(ID);
+  ID.AddPointer((void*) Data);
+
+  PersistentSValsTy& Map = *((PersistentSValsTy*) PersistentSVals);
+
+  typedef llvm::FoldingSetNodeWrapper<SValData> FoldNodeTy;
+  FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!P) {
+    P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
+    new (P) FoldNodeTy(std::make_pair(V, Data));
+    Map.InsertNode(P, InsertPos);
+  }
+
+  return P->getValue();
+}
+
+const std::pair<SVal, SVal>&
+BasicValueFactory::getPersistentSValPair(const SVal& V1, const SVal& V2) {
+
+  // Lazily create the folding set.
+  if (!PersistentSValPairs) PersistentSValPairs = new PersistentSValPairsTy();
+
+  llvm::FoldingSetNodeID ID;
+  void* InsertPos;
+  V1.Profile(ID);
+  V2.Profile(ID);
+
+  PersistentSValPairsTy& Map = *((PersistentSValPairsTy*) PersistentSValPairs);
+
+  typedef llvm::FoldingSetNodeWrapper<SValPair> FoldNodeTy;
+  FoldNodeTy* P = Map.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!P) {
+    P = (FoldNodeTy*) BPAlloc.Allocate<FoldNodeTy>();
+    new (P) FoldNodeTy(std::make_pair(V1, V2));
+    Map.InsertNode(P, InsertPos);
+  }
+
+  return P->getValue();
+}
+
+const SVal* BasicValueFactory::getPersistentSVal(SVal X) {
+  return &getPersistentSValWithData(X, 0).first;
+}
+
+
diff --git a/lib/StaticAnalyzer/EntoSA/BlockCounter.cpp b/lib/StaticAnalyzer/EntoSA/BlockCounter.cpp
new file mode 100644 (file)
index 0000000..47f6088
--- /dev/null
@@ -0,0 +1,86 @@
+//==- BlockCounter.h - ADT for counting block visits -------------*- 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 BlockCounter, an abstract data type used to count
+//  the number of times a given block has been visited along a path
+//  analyzed by CoreEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/BlockCounter.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class CountKey {
+  const StackFrameContext *CallSite;
+  unsigned BlockID;
+
+public:
+  CountKey(const StackFrameContext *CS, unsigned ID) 
+    : CallSite(CS), BlockID(ID) {}
+
+  bool operator==(const CountKey &RHS) const {
+    return (CallSite == RHS.CallSite) && (BlockID == RHS.BlockID);
+  }
+
+  bool operator<(const CountKey &RHS) const {
+    return (CallSite == RHS.CallSite) ? (BlockID < RHS.BlockID) 
+                                      : (CallSite < RHS.CallSite);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddPointer(CallSite);
+    ID.AddInteger(BlockID);
+  }
+};
+
+}
+
+typedef llvm::ImmutableMap<CountKey, unsigned> CountMap;
+
+static inline CountMap GetMap(void* D) {
+  return CountMap(static_cast<CountMap::TreeTy*>(D));
+}
+
+static inline CountMap::Factory& GetFactory(void* F) {
+  return *static_cast<CountMap::Factory*>(F);
+}
+
+unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite, 
+                                       unsigned BlockID) const {
+  CountMap M = GetMap(Data);
+  CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
+  return T ? *T : 0;
+}
+
+BlockCounter::Factory::Factory(llvm::BumpPtrAllocator& Alloc) {
+  F = new CountMap::Factory(Alloc);
+}
+
+BlockCounter::Factory::~Factory() {
+  delete static_cast<CountMap::Factory*>(F);
+}
+
+BlockCounter
+BlockCounter::Factory::IncrementCount(BlockCounter BC, 
+                                        const StackFrameContext *CallSite,
+                                        unsigned BlockID) {
+  return BlockCounter(GetFactory(F).add(GetMap(BC.Data), 
+                                          CountKey(CallSite, BlockID),
+                             BC.getNumVisited(CallSite, BlockID)+1).getRoot());
+}
+
+BlockCounter
+BlockCounter::Factory::GetEmptyCounter() {
+  return BlockCounter(GetFactory(F).getEmptyMap().getRoot());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/BugReporter.cpp b/lib/StaticAnalyzer/EntoSA/BugReporter.cpp
new file mode 100644 (file)
index 0000000..8edbe14
--- /dev/null
@@ -0,0 +1,1892 @@
+// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- 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 BugReporter, a utility class for generating
+//  PathDiagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/OwningPtr.h"
+#include <queue>
+
+using namespace clang;
+using namespace ento;
+
+BugReporterVisitor::~BugReporterVisitor() {}
+BugReporterContext::~BugReporterContext() {
+  for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I)
+    if ((*I)->isOwnedByReporterContext()) delete *I;
+}
+
+void BugReporterContext::addVisitor(BugReporterVisitor* visitor) {
+  if (!visitor)
+    return;
+
+  llvm::FoldingSetNodeID ID;
+  visitor->Profile(ID);
+  void *InsertPos;
+
+  if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
+    delete visitor;
+    return;
+  }
+
+  CallbacksSet.InsertNode(visitor, InsertPos);
+  Callbacks = F.add(visitor, Callbacks);
+}
+
+//===----------------------------------------------------------------------===//
+// Helper routines for walking the ExplodedGraph and fetching statements.
+//===----------------------------------------------------------------------===//
+
+static inline const Stmt* GetStmt(const ProgramPoint &P) {
+  if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P))
+    return SP->getStmt();
+  else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P))
+    return BE->getSrc()->getTerminator();
+
+  return 0;
+}
+
+static inline const ExplodedNode*
+GetPredecessorNode(const ExplodedNode* N) {
+  return N->pred_empty() ? NULL : *(N->pred_begin());
+}
+
+static inline const ExplodedNode*
+GetSuccessorNode(const ExplodedNode* N) {
+  return N->succ_empty() ? NULL : *(N->succ_begin());
+}
+
+static const Stmt* GetPreviousStmt(const ExplodedNode* N) {
+  for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N))
+    if (const Stmt *S = GetStmt(N->getLocation()))
+      return S;
+
+  return 0;
+}
+
+static const Stmt* GetNextStmt(const ExplodedNode* N) {
+  for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N))
+    if (const Stmt *S = GetStmt(N->getLocation())) {
+      // Check if the statement is '?' or '&&'/'||'.  These are "merges",
+      // not actual statement points.
+      switch (S->getStmtClass()) {
+        case Stmt::ChooseExprClass:
+        case Stmt::ConditionalOperatorClass: continue;
+        case Stmt::BinaryOperatorClass: {
+          BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
+          if (Op == BO_LAnd || Op == BO_LOr)
+            continue;
+          break;
+        }
+        default:
+          break;
+      }
+
+      // Some expressions don't have locations.
+      if (S->getLocStart().isInvalid())
+        continue;
+
+      return S;
+    }
+
+  return 0;
+}
+
+static inline const Stmt*
+GetCurrentOrPreviousStmt(const ExplodedNode* N) {
+  if (const Stmt *S = GetStmt(N->getLocation()))
+    return S;
+
+  return GetPreviousStmt(N);
+}
+
+static inline const Stmt*
+GetCurrentOrNextStmt(const ExplodedNode* N) {
+  if (const Stmt *S = GetStmt(N->getLocation()))
+    return S;
+
+  return GetNextStmt(N);
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnosticBuilder and its associated routines and helper objects.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::DenseMap<const ExplodedNode*,
+const ExplodedNode*> NodeBackMap;
+
+namespace {
+class NodeMapClosure : public BugReport::NodeResolver {
+  NodeBackMap& M;
+public:
+  NodeMapClosure(NodeBackMap *m) : M(*m) {}
+  ~NodeMapClosure() {}
+
+  const ExplodedNode* getOriginalNode(const ExplodedNode* N) {
+    NodeBackMap::iterator I = M.find(N);
+    return I == M.end() ? 0 : I->second;
+  }
+};
+
+class PathDiagnosticBuilder : public BugReporterContext {
+  BugReport *R;
+  PathDiagnosticClient *PDC;
+  llvm::OwningPtr<ParentMap> PM;
+  NodeMapClosure NMC;
+public:
+  PathDiagnosticBuilder(GRBugReporter &br,
+                        BugReport *r, NodeBackMap *Backmap,
+                        PathDiagnosticClient *pdc)
+    : BugReporterContext(br),
+      R(r), PDC(pdc), NMC(Backmap) {
+    addVisitor(R);
+  }
+
+  PathDiagnosticLocation ExecutionContinues(const ExplodedNode* N);
+
+  PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream& os,
+                                            const ExplodedNode* N);
+
+  Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); }
+
+  ParentMap& getParentMap() { return R->getErrorNode()->getParentMap(); }
+
+  const Stmt *getParent(const Stmt *S) {
+    return getParentMap().getParent(S);
+  }
+
+  virtual NodeMapClosure& getNodeResolver() { return NMC; }
+
+  PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
+
+  PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const {
+    return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive;
+  }
+
+  bool supportsLogicalOpControlFlow() const {
+    return PDC ? PDC->supportsLogicalOpControlFlow() : true;
+  }
+};
+} // end anonymous namespace
+
+PathDiagnosticLocation
+PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* N) {
+  if (const Stmt *S = GetNextStmt(N))
+    return PathDiagnosticLocation(S, getSourceManager());
+
+  return FullSourceLoc(N->getLocationContext()->getDecl()->getBodyRBrace(),
+                       getSourceManager());
+}
+
+PathDiagnosticLocation
+PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os,
+                                          const ExplodedNode* N) {
+
+  // Slow, but probably doesn't matter.
+  if (os.str().empty())
+    os << ' ';
+
+  const PathDiagnosticLocation &Loc = ExecutionContinues(N);
+
+  if (Loc.asStmt())
+    os << "Execution continues on line "
+       << getSourceManager().getInstantiationLineNumber(Loc.asLocation())
+       << '.';
+  else {
+    os << "Execution jumps to the end of the ";
+    const Decl *D = N->getLocationContext()->getDecl();
+    if (isa<ObjCMethodDecl>(D))
+      os << "method";
+    else if (isa<FunctionDecl>(D))
+      os << "function";
+    else {
+      assert(isa<BlockDecl>(D));
+      os << "anonymous block";
+    }
+    os << '.';
+  }
+
+  return Loc;
+}
+
+static bool IsNested(const Stmt *S, ParentMap &PM) {
+  if (isa<Expr>(S) && PM.isConsumedExpr(cast<Expr>(S)))
+    return true;
+
+  const Stmt *Parent = PM.getParentIgnoreParens(S);
+
+  if (Parent)
+    switch (Parent->getStmtClass()) {
+      case Stmt::ForStmtClass:
+      case Stmt::DoStmtClass:
+      case Stmt::WhileStmtClass:
+        return true;
+      default:
+        break;
+    }
+
+  return false;
+}
+
+PathDiagnosticLocation
+PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
+  assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
+  ParentMap &P = getParentMap();
+  SourceManager &SMgr = getSourceManager();
+
+  while (IsNested(S, P)) {
+    const Stmt *Parent = P.getParentIgnoreParens(S);
+
+    if (!Parent)
+      break;
+
+    switch (Parent->getStmtClass()) {
+      case Stmt::BinaryOperatorClass: {
+        const BinaryOperator *B = cast<BinaryOperator>(Parent);
+        if (B->isLogicalOp())
+          return PathDiagnosticLocation(S, SMgr);
+        break;
+      }
+      case Stmt::CompoundStmtClass:
+      case Stmt::StmtExprClass:
+        return PathDiagnosticLocation(S, SMgr);
+      case Stmt::ChooseExprClass:
+        // Similar to '?' if we are referring to condition, just have the edge
+        // point to the entire choose expression.
+        if (cast<ChooseExpr>(Parent)->getCond() == S)
+          return PathDiagnosticLocation(Parent, SMgr);
+        else
+          return PathDiagnosticLocation(S, SMgr);
+      case Stmt::ConditionalOperatorClass:
+        // For '?', if we are referring to condition, just have the edge point
+        // to the entire '?' expression.
+        if (cast<ConditionalOperator>(Parent)->getCond() == S)
+          return PathDiagnosticLocation(Parent, SMgr);
+        else
+          return PathDiagnosticLocation(S, SMgr);
+      case Stmt::DoStmtClass:
+          return PathDiagnosticLocation(S, SMgr);
+      case Stmt::ForStmtClass:
+        if (cast<ForStmt>(Parent)->getBody() == S)
+          return PathDiagnosticLocation(S, SMgr);
+        break;
+      case Stmt::IfStmtClass:
+        if (cast<IfStmt>(Parent)->getCond() != S)
+          return PathDiagnosticLocation(S, SMgr);
+        break;
+      case Stmt::ObjCForCollectionStmtClass:
+        if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
+          return PathDiagnosticLocation(S, SMgr);
+        break;
+      case Stmt::WhileStmtClass:
+        if (cast<WhileStmt>(Parent)->getCond() != S)
+          return PathDiagnosticLocation(S, SMgr);
+        break;
+      default:
+        break;
+    }
+
+    S = Parent;
+  }
+
+  assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
+
+  // Special case: DeclStmts can appear in for statement declarations, in which
+  //  case the ForStmt is the context.
+  if (isa<DeclStmt>(S)) {
+    if (const Stmt *Parent = P.getParent(S)) {
+      switch (Parent->getStmtClass()) {
+        case Stmt::ForStmtClass:
+        case Stmt::ObjCForCollectionStmtClass:
+          return PathDiagnosticLocation(Parent, SMgr);
+        default:
+          break;
+      }
+    }
+  }
+  else if (isa<BinaryOperator>(S)) {
+    // Special case: the binary operator represents the initialization
+    // code in a for statement (this can happen when the variable being
+    // initialized is an old variable.
+    if (const ForStmt *FS =
+          dyn_cast_or_null<ForStmt>(P.getParentIgnoreParens(S))) {
+      if (FS->getInit() == S)
+        return PathDiagnosticLocation(FS, SMgr);
+    }
+  }
+
+  return PathDiagnosticLocation(S, SMgr);
+}
+
+//===----------------------------------------------------------------------===//
+// ScanNotableSymbols: closure-like callback for scanning Store bindings.
+//===----------------------------------------------------------------------===//
+
+static const VarDecl*
+GetMostRecentVarDeclBinding(const ExplodedNode* N,
+                            GRStateManager& VMgr, SVal X) {
+
+  for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
+
+    ProgramPoint P = N->getLocation();
+
+    if (!isa<PostStmt>(P))
+      continue;
+
+    const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
+
+    if (!DR)
+      continue;
+
+    SVal Y = N->getState()->getSVal(DR);
+
+    if (X != Y)
+      continue;
+
+    const VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
+
+    if (!VD)
+      continue;
+
+    return VD;
+  }
+
+  return 0;
+}
+
+namespace {
+class NotableSymbolHandler
+: public StoreManager::BindingsHandler {
+
+  SymbolRef Sym;
+  const GRState* PrevSt;
+  const Stmt* S;
+  GRStateManager& VMgr;
+  const ExplodedNode* Pred;
+  PathDiagnostic& PD;
+  BugReporter& BR;
+
+public:
+
+  NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s,
+                       GRStateManager& vmgr, const ExplodedNode* pred,
+                       PathDiagnostic& pd, BugReporter& br)
+  : Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {}
+
+  bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
+                     SVal V) {
+
+    SymbolRef ScanSym = V.getAsSymbol();
+
+    if (ScanSym != Sym)
+      return true;
+
+    // Check if the previous state has this binding.
+    SVal X = PrevSt->getSVal(loc::MemRegionVal(R));
+
+    if (X == V) // Same binding?
+      return true;
+
+    // Different binding.  Only handle assignments for now.  We don't pull
+    // this check out of the loop because we will eventually handle other
+    // cases.
+
+    VarDecl *VD = 0;
+
+    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+      if (!B->isAssignmentOp())
+        return true;
+
+      // What variable did we assign to?
+      DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
+
+      if (!DR)
+        return true;
+
+      VD = dyn_cast<VarDecl>(DR->getDecl());
+    }
+    else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+      // FIXME: Eventually CFGs won't have DeclStmts.  Right now we
+      //  assume that each DeclStmt has a single Decl.  This invariant
+      //  holds by contruction in the CFG.
+      VD = dyn_cast<VarDecl>(*DS->decl_begin());
+    }
+
+    if (!VD)
+      return true;
+
+    // What is the most recently referenced variable with this binding?
+    const VarDecl* MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
+
+    if (!MostRecent)
+      return true;
+
+    // Create the diagnostic.
+    FullSourceLoc L(S->getLocStart(), BR.getSourceManager());
+
+    if (Loc::IsLocType(VD->getType())) {
+      std::string msg = "'" + std::string(VD->getNameAsString()) +
+      "' now aliases '" + MostRecent->getNameAsString() + "'";
+
+      PD.push_front(new PathDiagnosticEventPiece(L, msg));
+    }
+
+    return true;
+  }
+};
+}
+
+static void HandleNotableSymbol(const ExplodedNode* N,
+                                const Stmt* S,
+                                SymbolRef Sym, BugReporter& BR,
+                                PathDiagnostic& PD) {
+
+  const ExplodedNode* Pred = N->pred_empty() ? 0 : *N->pred_begin();
+  const GRState* PrevSt = Pred ? Pred->getState() : 0;
+
+  if (!PrevSt)
+    return;
+
+  // Look at the region bindings of the current state that map to the
+  // specified symbol.  Are any of them not in the previous state?
+  GRStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
+  NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
+  cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
+}
+
+namespace {
+class ScanNotableSymbols
+: public StoreManager::BindingsHandler {
+
+  llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
+  const ExplodedNode* N;
+  const Stmt* S;
+  GRBugReporter& BR;
+  PathDiagnostic& PD;
+
+public:
+  ScanNotableSymbols(const ExplodedNode* n, const Stmt* s,
+                     GRBugReporter& br, PathDiagnostic& pd)
+  : N(n), S(s), BR(br), PD(pd) {}
+
+  bool HandleBinding(StoreManager& SMgr, Store store,
+                     const MemRegion* R, SVal V) {
+
+    SymbolRef ScanSym = V.getAsSymbol();
+
+    if (!ScanSym)
+      return true;
+
+    if (!BR.isNotable(ScanSym))
+      return true;
+
+    if (AlreadyProcessed.count(ScanSym))
+      return true;
+
+    AlreadyProcessed.insert(ScanSym);
+
+    HandleNotableSymbol(N, S, ScanSym, BR, PD);
+    return true;
+  }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// "Minimal" path diagnostic generation algorithm.
+//===----------------------------------------------------------------------===//
+
+static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM);
+
+static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
+                                          PathDiagnosticBuilder &PDB,
+                                          const ExplodedNode *N) {
+
+  SourceManager& SMgr = PDB.getSourceManager();
+  const ExplodedNode* NextNode = N->pred_empty()
+                                        ? NULL : *(N->pred_begin());
+  while (NextNode) {
+    N = NextNode;
+    NextNode = GetPredecessorNode(N);
+
+    ProgramPoint P = N->getLocation();
+
+    if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
+      const CFGBlock* Src = BE->getSrc();
+      const CFGBlock* Dst = BE->getDst();
+      const Stmt* T = Src->getTerminator();
+
+      if (!T)
+        continue;
+
+      FullSourceLoc Start(T->getLocStart(), SMgr);
+
+      switch (T->getStmtClass()) {
+        default:
+          break;
+
+        case Stmt::GotoStmtClass:
+        case Stmt::IndirectGotoStmtClass: {
+          const Stmt* S = GetNextStmt(N);
+
+          if (!S)
+            continue;
+
+          std::string sbuf;
+          llvm::raw_string_ostream os(sbuf);
+          const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
+
+          os << "Control jumps to line "
+          << End.asLocation().getInstantiationLineNumber();
+          PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                           os.str()));
+          break;
+        }
+
+        case Stmt::SwitchStmtClass: {
+          // Figure out what case arm we took.
+          std::string sbuf;
+          llvm::raw_string_ostream os(sbuf);
+
+          if (const Stmt* S = Dst->getLabel()) {
+            PathDiagnosticLocation End(S, SMgr);
+
+            switch (S->getStmtClass()) {
+              default:
+                os << "No cases match in the switch statement. "
+                "Control jumps to line "
+                << End.asLocation().getInstantiationLineNumber();
+                break;
+              case Stmt::DefaultStmtClass:
+                os << "Control jumps to the 'default' case at line "
+                << End.asLocation().getInstantiationLineNumber();
+                break;
+
+              case Stmt::CaseStmtClass: {
+                os << "Control jumps to 'case ";
+                const CaseStmt* Case = cast<CaseStmt>(S);
+                const Expr* LHS = Case->getLHS()->IgnoreParenCasts();
+
+                // Determine if it is an enum.
+                bool GetRawInt = true;
+
+                if (const DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) {
+                  // FIXME: Maybe this should be an assertion.  Are there cases
+                  // were it is not an EnumConstantDecl?
+                  const EnumConstantDecl* D =
+                    dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+                  if (D) {
+                    GetRawInt = false;
+                    os << D;
+                  }
+                }
+
+                if (GetRawInt)
+                  os << LHS->EvaluateAsInt(PDB.getASTContext());
+
+                os << ":'  at line "
+                << End.asLocation().getInstantiationLineNumber();
+                break;
+              }
+            }
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                             os.str()));
+          }
+          else {
+            os << "'Default' branch taken. ";
+            const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N);
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                             os.str()));
+          }
+
+          break;
+        }
+
+        case Stmt::BreakStmtClass:
+        case Stmt::ContinueStmtClass: {
+          std::string sbuf;
+          llvm::raw_string_ostream os(sbuf);
+          PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+          PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                           os.str()));
+          break;
+        }
+
+          // Determine control-flow for ternary '?'.
+        case Stmt::ConditionalOperatorClass: {
+          std::string sbuf;
+          llvm::raw_string_ostream os(sbuf);
+          os << "'?' condition is ";
+
+          if (*(Src->succ_begin()+1) == Dst)
+            os << "false";
+          else
+            os << "true";
+
+          PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+
+          if (const Stmt *S = End.asStmt())
+            End = PDB.getEnclosingStmtLocation(S);
+
+          PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                           os.str()));
+          break;
+        }
+
+          // Determine control-flow for short-circuited '&&' and '||'.
+        case Stmt::BinaryOperatorClass: {
+          if (!PDB.supportsLogicalOpControlFlow())
+            break;
+
+          const BinaryOperator *B = cast<BinaryOperator>(T);
+          std::string sbuf;
+          llvm::raw_string_ostream os(sbuf);
+          os << "Left side of '";
+
+          if (B->getOpcode() == BO_LAnd) {
+            os << "&&" << "' is ";
+
+            if (*(Src->succ_begin()+1) == Dst) {
+              os << "false";
+              PathDiagnosticLocation End(B->getLHS(), SMgr);
+              PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr);
+              PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                               os.str()));
+            }
+            else {
+              os << "true";
+              PathDiagnosticLocation Start(B->getLHS(), SMgr);
+              PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+              PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                               os.str()));
+            }
+          }
+          else {
+            assert(B->getOpcode() == BO_LOr);
+            os << "||" << "' is ";
+
+            if (*(Src->succ_begin()+1) == Dst) {
+              os << "false";
+              PathDiagnosticLocation Start(B->getLHS(), SMgr);
+              PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+              PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                               os.str()));
+            }
+            else {
+              os << "true";
+              PathDiagnosticLocation End(B->getLHS(), SMgr);
+              PathDiagnosticLocation Start(B->getOperatorLoc(), SMgr);
+              PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                               os.str()));
+            }
+          }
+
+          break;
+        }
+
+        case Stmt::DoStmtClass:  {
+          if (*(Src->succ_begin()) == Dst) {
+            std::string sbuf;
+            llvm::raw_string_ostream os(sbuf);
+
+            os << "Loop condition is true. ";
+            PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+
+            if (const Stmt *S = End.asStmt())
+              End = PDB.getEnclosingStmtLocation(S);
+
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                             os.str()));
+          }
+          else {
+            PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+
+            if (const Stmt *S = End.asStmt())
+              End = PDB.getEnclosingStmtLocation(S);
+
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                              "Loop condition is false.  Exiting loop"));
+          }
+
+          break;
+        }
+
+        case Stmt::WhileStmtClass:
+        case Stmt::ForStmtClass: {
+          if (*(Src->succ_begin()+1) == Dst) {
+            std::string sbuf;
+            llvm::raw_string_ostream os(sbuf);
+
+            os << "Loop condition is false. ";
+            PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+            if (const Stmt *S = End.asStmt())
+              End = PDB.getEnclosingStmtLocation(S);
+
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                             os.str()));
+          }
+          else {
+            PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+            if (const Stmt *S = End.asStmt())
+              End = PDB.getEnclosingStmtLocation(S);
+
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                            "Loop condition is true.  Entering loop body"));
+          }
+
+          break;
+        }
+
+        case Stmt::IfStmtClass: {
+          PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+
+          if (const Stmt *S = End.asStmt())
+            End = PDB.getEnclosingStmtLocation(S);
+
+          if (*(Src->succ_begin()+1) == Dst)
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                        "Taking false branch"));
+          else
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                         "Taking true branch"));
+
+          break;
+        }
+      }
+    }
+
+    if (NextNode) {
+      for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(),
+           E = PDB.visitor_end(); I!=E; ++I) {
+        if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB))
+          PD.push_front(p);
+      }
+    }
+
+    if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
+      // Scan the region bindings, and see if a "notable" symbol has a new
+      // lval binding.
+      ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
+      PDB.getStateManager().iterBindings(N->getState(), SNS);
+    }
+  }
+
+  // After constructing the full PathDiagnostic, do a pass over it to compact
+  // PathDiagnosticPieces that occur within a macro.
+  CompactPathDiagnostic(PD, PDB.getSourceManager());
+}
+
+//===----------------------------------------------------------------------===//
+// "Extensive" PathDiagnostic generation.
+//===----------------------------------------------------------------------===//
+
+static bool IsControlFlowExpr(const Stmt *S) {
+  const Expr *E = dyn_cast<Expr>(S);
+
+  if (!E)
+    return false;
+
+  E = E->IgnoreParenCasts();
+
+  if (isa<ConditionalOperator>(E))
+    return true;
+
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E))
+    if (B->isLogicalOp())
+      return true;
+
+  return false;
+}
+
+namespace {
+class ContextLocation : public PathDiagnosticLocation {
+  bool IsDead;
+public:
+  ContextLocation(const PathDiagnosticLocation &L, bool isdead = false)
+    : PathDiagnosticLocation(L), IsDead(isdead) {}
+
+  void markDead() { IsDead = true; }
+  bool isDead() const { return IsDead; }
+};
+
+class EdgeBuilder {
+  std::vector<ContextLocation> CLocs;
+  typedef std::vector<ContextLocation>::iterator iterator;
+  PathDiagnostic &PD;
+  PathDiagnosticBuilder &PDB;
+  PathDiagnosticLocation PrevLoc;
+
+  bool IsConsumedExpr(const PathDiagnosticLocation &L);
+
+  bool containsLocation(const PathDiagnosticLocation &Container,
+                        const PathDiagnosticLocation &Containee);
+
+  PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L);
+
+  PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L,
+                                         bool firstCharOnly = false) {
+    if (const Stmt *S = L.asStmt()) {
+      const Stmt *Original = S;
+      while (1) {
+        // Adjust the location for some expressions that are best referenced
+        // by one of their subexpressions.
+        switch (S->getStmtClass()) {
+          default:
+            break;
+          case Stmt::ParenExprClass:
+            S = cast<ParenExpr>(S)->IgnoreParens();
+            firstCharOnly = true;
+            continue;
+          case Stmt::ConditionalOperatorClass:
+            S = cast<ConditionalOperator>(S)->getCond();
+            firstCharOnly = true;
+            continue;
+          case Stmt::ChooseExprClass:
+            S = cast<ChooseExpr>(S)->getCond();
+            firstCharOnly = true;
+            continue;
+          case Stmt::BinaryOperatorClass:
+            S = cast<BinaryOperator>(S)->getLHS();
+            firstCharOnly = true;
+            continue;
+        }
+
+        break;
+      }
+
+      if (S != Original)
+        L = PathDiagnosticLocation(S, L.getManager());
+    }
+
+    if (firstCharOnly)
+      L = PathDiagnosticLocation(L.asLocation());
+
+    return L;
+  }
+
+  void popLocation() {
+    if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) {
+      // For contexts, we only one the first character as the range.
+      rawAddEdge(cleanUpLocation(CLocs.back(), true));
+    }
+    CLocs.pop_back();
+  }
+
+public:
+  EdgeBuilder(PathDiagnostic &pd, PathDiagnosticBuilder &pdb)
+    : PD(pd), PDB(pdb) {
+
+      // If the PathDiagnostic already has pieces, add the enclosing statement
+      // of the first piece as a context as well.
+      if (!PD.empty()) {
+        PrevLoc = PD.begin()->getLocation();
+
+        if (const Stmt *S = PrevLoc.asStmt())
+          addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+      }
+  }
+
+  ~EdgeBuilder() {
+    while (!CLocs.empty()) popLocation();
+
+    // Finally, add an initial edge from the start location of the first
+    // statement (if it doesn't already exist).
+    // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
+    if (const CompoundStmt *CS =
+          dyn_cast_or_null<CompoundStmt>(PDB.getCodeDecl().getBody()))
+      if (!CS->body_empty()) {
+        SourceLocation Loc = (*CS->body_begin())->getLocStart();
+        rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager()));
+      }
+
+  }
+
+  void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false);
+
+  void rawAddEdge(PathDiagnosticLocation NewLoc);
+
+  void addContext(const Stmt *S);
+  void addExtendedContext(const Stmt *S);
+};
+} // end anonymous namespace
+
+
+PathDiagnosticLocation
+EdgeBuilder::getContextLocation(const PathDiagnosticLocation &L) {
+  if (const Stmt *S = L.asStmt()) {
+    if (IsControlFlowExpr(S))
+      return L;
+
+    return PDB.getEnclosingStmtLocation(S);
+  }
+
+  return L;
+}
+
+bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container,
+                                   const PathDiagnosticLocation &Containee) {
+
+  if (Container == Containee)
+    return true;
+
+  if (Container.asDecl())
+    return true;
+
+  if (const Stmt *S = Containee.asStmt())
+    if (const Stmt *ContainerS = Container.asStmt()) {
+      while (S) {
+        if (S == ContainerS)
+          return true;
+        S = PDB.getParent(S);
+      }
+      return false;
+    }
+
+  // Less accurate: compare using source ranges.
+  SourceRange ContainerR = Container.asRange();
+  SourceRange ContaineeR = Containee.asRange();
+
+  SourceManager &SM = PDB.getSourceManager();
+  SourceLocation ContainerRBeg = SM.getInstantiationLoc(ContainerR.getBegin());
+  SourceLocation ContainerREnd = SM.getInstantiationLoc(ContainerR.getEnd());
+  SourceLocation ContaineeRBeg = SM.getInstantiationLoc(ContaineeR.getBegin());
+  SourceLocation ContaineeREnd = SM.getInstantiationLoc(ContaineeR.getEnd());
+
+  unsigned ContainerBegLine = SM.getInstantiationLineNumber(ContainerRBeg);
+  unsigned ContainerEndLine = SM.getInstantiationLineNumber(ContainerREnd);
+  unsigned ContaineeBegLine = SM.getInstantiationLineNumber(ContaineeRBeg);
+  unsigned ContaineeEndLine = SM.getInstantiationLineNumber(ContaineeREnd);
+
+  assert(ContainerBegLine <= ContainerEndLine);
+  assert(ContaineeBegLine <= ContaineeEndLine);
+
+  return (ContainerBegLine <= ContaineeBegLine &&
+          ContainerEndLine >= ContaineeEndLine &&
+          (ContainerBegLine != ContaineeBegLine ||
+           SM.getInstantiationColumnNumber(ContainerRBeg) <=
+           SM.getInstantiationColumnNumber(ContaineeRBeg)) &&
+          (ContainerEndLine != ContaineeEndLine ||
+           SM.getInstantiationColumnNumber(ContainerREnd) >=
+           SM.getInstantiationColumnNumber(ContainerREnd)));
+}
+
+void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
+  if (!PrevLoc.isValid()) {
+    PrevLoc = NewLoc;
+    return;
+  }
+
+  const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc);
+  const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc);
+
+  if (NewLocClean.asLocation() == PrevLocClean.asLocation())
+    return;
+
+  // FIXME: Ignore intra-macro edges for now.
+  if (NewLocClean.asLocation().getInstantiationLoc() ==
+      PrevLocClean.asLocation().getInstantiationLoc())
+    return;
+
+  PD.push_front(new PathDiagnosticControlFlowPiece(NewLocClean, PrevLocClean));
+  PrevLoc = NewLoc;
+}
+
+void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) {
+
+  if (!alwaysAdd && NewLoc.asLocation().isMacroID())
+    return;
+
+  const PathDiagnosticLocation &CLoc = getContextLocation(NewLoc);
+
+  while (!CLocs.empty()) {
+    ContextLocation &TopContextLoc = CLocs.back();
+
+    // Is the top location context the same as the one for the new location?
+    if (TopContextLoc == CLoc) {
+      if (alwaysAdd) {
+        if (IsConsumedExpr(TopContextLoc) &&
+            !IsControlFlowExpr(TopContextLoc.asStmt()))
+            TopContextLoc.markDead();
+
+        rawAddEdge(NewLoc);
+      }
+
+      return;
+    }
+
+    if (containsLocation(TopContextLoc, CLoc)) {
+      if (alwaysAdd) {
+        rawAddEdge(NewLoc);
+
+        if (IsConsumedExpr(CLoc) && !IsControlFlowExpr(CLoc.asStmt())) {
+          CLocs.push_back(ContextLocation(CLoc, true));
+          return;
+        }
+      }
+
+      CLocs.push_back(CLoc);
+      return;
+    }
+
+    // Context does not contain the location.  Flush it.
+    popLocation();
+  }
+
+  // If we reach here, there is no enclosing context.  Just add the edge.
+  rawAddEdge(NewLoc);
+}
+
+bool EdgeBuilder::IsConsumedExpr(const PathDiagnosticLocation &L) {
+  if (const Expr *X = dyn_cast_or_null<Expr>(L.asStmt()))
+    return PDB.getParentMap().isConsumedExpr(X) && !IsControlFlowExpr(X);
+
+  return false;
+}
+
+void EdgeBuilder::addExtendedContext(const Stmt *S) {
+  if (!S)
+    return;
+
+  const Stmt *Parent = PDB.getParent(S);
+  while (Parent) {
+    if (isa<CompoundStmt>(Parent))
+      Parent = PDB.getParent(Parent);
+    else
+      break;
+  }
+
+  if (Parent) {
+    switch (Parent->getStmtClass()) {
+      case Stmt::DoStmtClass:
+      case Stmt::ObjCAtSynchronizedStmtClass:
+        addContext(Parent);
+      default:
+        break;
+    }
+  }
+
+  addContext(S);
+}
+
+void EdgeBuilder::addContext(const Stmt *S) {
+  if (!S)
+    return;
+
+  PathDiagnosticLocation L(S, PDB.getSourceManager());
+
+  while (!CLocs.empty()) {
+    const PathDiagnosticLocation &TopContextLoc = CLocs.back();
+
+    // Is the top location context the same as the one for the new location?
+    if (TopContextLoc == L)
+      return;
+
+    if (containsLocation(TopContextLoc, L)) {
+      CLocs.push_back(L);
+      return;
+    }
+
+    // Context does not contain the location.  Flush it.
+    popLocation();
+  }
+
+  CLocs.push_back(L);
+}
+
+static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
+                                            PathDiagnosticBuilder &PDB,
+                                            const ExplodedNode *N) {
+  EdgeBuilder EB(PD, PDB);
+
+  const ExplodedNode* NextNode = N->pred_empty() ? NULL : *(N->pred_begin());
+  while (NextNode) {
+    N = NextNode;
+    NextNode = GetPredecessorNode(N);
+    ProgramPoint P = N->getLocation();
+
+    do {
+      // Block edges.
+      if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+        const CFGBlock &Blk = *BE->getSrc();
+        const Stmt *Term = Blk.getTerminator();
+
+        // Are we jumping to the head of a loop?  Add a special diagnostic.
+        if (const Stmt *Loop = BE->getDst()->getLoopTarget()) {
+          PathDiagnosticLocation L(Loop, PDB.getSourceManager());
+          const CompoundStmt *CS = NULL;
+
+          if (!Term) {
+            if (const ForStmt *FS = dyn_cast<ForStmt>(Loop))
+              CS = dyn_cast<CompoundStmt>(FS->getBody());
+            else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop))
+              CS = dyn_cast<CompoundStmt>(WS->getBody());
+          }
+
+          PathDiagnosticEventPiece *p =
+            new PathDiagnosticEventPiece(L,
+                                        "Looping back to the head of the loop");
+
+          EB.addEdge(p->getLocation(), true);
+          PD.push_front(p);
+
+          if (CS) {
+            PathDiagnosticLocation BL(CS->getRBracLoc(),
+                                      PDB.getSourceManager());
+            BL = PathDiagnosticLocation(BL.asLocation());
+            EB.addEdge(BL);
+          }
+        }
+
+        if (Term)
+          EB.addContext(Term);
+
+        break;
+      }
+
+      if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+        if (CFGStmt S = BE->getFirstElement().getAs<CFGStmt>()) {
+          if (IsControlFlowExpr(S)) {
+            // Add the proper context for '&&', '||', and '?'.
+            EB.addContext(S);
+          }
+          else
+            EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+        }
+        
+        break;
+      }
+    } while (0);
+
+    if (!NextNode)
+      continue;
+
+    for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(),
+         E = PDB.visitor_end(); I!=E; ++I) {
+      if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB)) {
+        const PathDiagnosticLocation &Loc = p->getLocation();
+        EB.addEdge(Loc, true);
+        PD.push_front(p);
+        if (const Stmt *S = Loc.asStmt())
+          EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());
+      }
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugType and subclasses.
+//===----------------------------------------------------------------------===//
+BugType::~BugType() {
+  // Free up the equivalence class objects.  Observe that we get a pointer to
+  // the object first before incrementing the iterator, as destroying the
+  // node before doing so means we will read from freed memory.
+  for (iterator I = begin(), E = end(); I !=E; ) {
+    BugReportEquivClass *EQ = &*I;
+    ++I;
+    delete EQ;
+  }
+}
+void BugType::FlushReports(BugReporter &BR) {}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugReport and subclasses.
+//===----------------------------------------------------------------------===//
+BugReport::~BugReport() {}
+RangedBugReport::~RangedBugReport() {}
+
+const Stmt* BugReport::getStmt() const {
+  ProgramPoint ProgP = ErrorNode->getLocation();
+  const Stmt *S = NULL;
+
+  if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP)) {
+    CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
+    if (BE->getBlock() == &Exit)
+      S = GetPreviousStmt(ErrorNode);
+  }
+  if (!S)
+    S = GetStmt(ProgP);
+
+  return S;
+}
+
+PathDiagnosticPiece*
+BugReport::getEndPath(BugReporterContext& BRC,
+                      const ExplodedNode* EndPathNode) {
+
+  const Stmt* S = getStmt();
+
+  if (!S)
+    return NULL;
+
+  BugReport::ranges_iterator Beg, End;
+  llvm::tie(Beg, End) = getRanges();
+  PathDiagnosticLocation L(S, BRC.getSourceManager());
+
+  // Only add the statement itself as a range if we didn't specify any
+  // special ranges for this report.
+  PathDiagnosticPiece* P = new PathDiagnosticEventPiece(L, getDescription(),
+                                                        Beg == End);
+
+  for (; Beg != End; ++Beg)
+    P->addRange(*Beg);
+
+  return P;
+}
+
+std::pair<BugReport::ranges_iterator, BugReport::ranges_iterator>
+BugReport::getRanges() const {
+  if (const Expr* E = dyn_cast_or_null<Expr>(getStmt())) {
+    R = E->getSourceRange();
+    assert(R.isValid());
+    return std::make_pair(&R, &R+1);
+  }
+  else
+    return std::make_pair(ranges_iterator(), ranges_iterator());
+}
+
+SourceLocation BugReport::getLocation() const {
+  if (ErrorNode)
+    if (const Stmt* S = GetCurrentOrPreviousStmt(ErrorNode)) {
+      // For member expressions, return the location of the '.' or '->'.
+      if (const MemberExpr *ME = dyn_cast<MemberExpr>(S))
+        return ME->getMemberLoc();
+      // For binary operators, return the location of the operator.
+      if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
+        return B->getOperatorLoc();
+
+      return S->getLocStart();
+    }
+
+  return FullSourceLoc();
+}
+
+PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode* N,
+                                          const ExplodedNode* PrevN,
+                                          BugReporterContext &BRC) {
+  return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugReporter and subclasses.
+//===----------------------------------------------------------------------===//
+
+BugReportEquivClass::~BugReportEquivClass() {
+  for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
+}
+
+GRBugReporter::~GRBugReporter() { }
+BugReporterData::~BugReporterData() {}
+
+ExplodedGraph &GRBugReporter::getGraph() { return Eng.getGraph(); }
+
+GRStateManager&
+GRBugReporter::getStateManager() { return Eng.getStateManager(); }
+
+BugReporter::~BugReporter() { FlushReports(); }
+
+void BugReporter::FlushReports() {
+  if (BugTypes.isEmpty())
+    return;
+
+  // First flush the warnings for each BugType.  This may end up creating new
+  // warnings and new BugTypes.  Because ImmutableSet is a functional data
+  // structure, we do not need to worry about the iterators being invalidated.
+  for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
+    const_cast<BugType*>(*I)->FlushReports(*this);
+
+  // Iterate through BugTypes a second time.  BugTypes may have been updated
+  // with new BugType objects and new warnings.
+  for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I) {
+    BugType *BT = const_cast<BugType*>(*I);
+
+    typedef llvm::FoldingSet<BugReportEquivClass> SetTy;
+    SetTy& EQClasses = BT->EQClasses;
+
+    for (SetTy::iterator EI=EQClasses.begin(), EE=EQClasses.end(); EI!=EE;++EI){
+      BugReportEquivClass& EQ = *EI;
+      FlushReport(EQ);
+    }
+
+    // Delete the BugType object.
+    delete BT;
+  }
+
+  // Remove all references to the BugType objects.
+  BugTypes = F.getEmptySet();
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnostics generation.
+//===----------------------------------------------------------------------===//
+
+static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
+                 std::pair<ExplodedNode*, unsigned> >
+MakeReportGraph(const ExplodedGraph* G,
+                llvm::SmallVectorImpl<const ExplodedNode*> &nodes) {
+
+  // Create the trimmed graph.  It will contain the shortest paths from the
+  // error nodes to the root.  In the new graph we should only have one
+  // error node unless there are two or more error nodes with the same minimum
+  // path length.
+  ExplodedGraph* GTrim;
+  InterExplodedGraphMap* NMap;
+
+  llvm::DenseMap<const void*, const void*> InverseMap;
+  llvm::tie(GTrim, NMap) = G->Trim(nodes.data(), nodes.data() + nodes.size(),
+                                   &InverseMap);
+
+  // Create owning pointers for GTrim and NMap just to ensure that they are
+  // released when this function exists.
+  llvm::OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim);
+  llvm::OwningPtr<InterExplodedGraphMap> AutoReleaseNMap(NMap);
+
+  // Find the (first) error node in the trimmed graph.  We just need to consult
+  // the node map (NMap) which maps from nodes in the original graph to nodes
+  // in the new graph.
+
+  std::queue<const ExplodedNode*> WS;
+  typedef llvm::DenseMap<const ExplodedNode*, unsigned> IndexMapTy;
+  IndexMapTy IndexMap;
+
+  for (unsigned nodeIndex = 0 ; nodeIndex < nodes.size(); ++nodeIndex) {
+    const ExplodedNode *originalNode = nodes[nodeIndex];
+    if (const ExplodedNode *N = NMap->getMappedNode(originalNode)) {
+      WS.push(N);
+      IndexMap[originalNode] = nodeIndex;
+    }
+  }
+
+  assert(!WS.empty() && "No error node found in the trimmed graph.");
+
+  // Create a new (third!) graph with a single path.  This is the graph
+  // that will be returned to the caller.
+  ExplodedGraph *GNew = new ExplodedGraph();
+
+  // Sometimes the trimmed graph can contain a cycle.  Perform a reverse BFS
+  // to the root node, and then construct a new graph that contains only
+  // a single path.
+  llvm::DenseMap<const void*,unsigned> Visited;
+
+  unsigned cnt = 0;
+  const ExplodedNode* Root = 0;
+
+  while (!WS.empty()) {
+    const ExplodedNode* Node = WS.front();
+    WS.pop();
+
+    if (Visited.find(Node) != Visited.end())
+      continue;
+
+    Visited[Node] = cnt++;
+
+    if (Node->pred_empty()) {
+      Root = Node;
+      break;
+    }
+
+    for (ExplodedNode::const_pred_iterator I=Node->pred_begin(),
+         E=Node->pred_end(); I!=E; ++I)
+      WS.push(*I);
+  }
+
+  assert(Root);
+
+  // Now walk from the root down the BFS path, always taking the successor
+  // with the lowest number.
+  ExplodedNode *Last = 0, *First = 0;
+  NodeBackMap *BM = new NodeBackMap();
+  unsigned NodeIndex = 0;
+
+  for ( const ExplodedNode *N = Root ;;) {
+    // Lookup the number associated with the current node.
+    llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
+    assert(I != Visited.end());
+
+    // Create the equivalent node in the new graph with the same state
+    // and location.
+    ExplodedNode* NewN = GNew->getNode(N->getLocation(), N->getState());
+
+    // Store the mapping to the original node.
+    llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
+    assert(IMitr != InverseMap.end() && "No mapping to original node.");
+    (*BM)[NewN] = (const ExplodedNode*) IMitr->second;
+
+    // Link up the new node with the previous node.
+    if (Last)
+      NewN->addPredecessor(Last, *GNew);
+
+    Last = NewN;
+
+    // Are we at the final node?
+    IndexMapTy::iterator IMI =
+      IndexMap.find((const ExplodedNode*)(IMitr->second));
+    if (IMI != IndexMap.end()) {
+      First = NewN;
+      NodeIndex = IMI->second;
+      break;
+    }
+
+    // Find the next successor node.  We choose the node that is marked
+    // with the lowest DFS number.
+    ExplodedNode::const_succ_iterator SI = N->succ_begin();
+    ExplodedNode::const_succ_iterator SE = N->succ_end();
+    N = 0;
+
+    for (unsigned MinVal = 0; SI != SE; ++SI) {
+
+      I = Visited.find(*SI);
+
+      if (I == Visited.end())
+        continue;
+
+      if (!N || I->second < MinVal) {
+        N = *SI;
+        MinVal = I->second;
+      }
+    }
+
+    assert(N);
+  }
+
+  assert(First);
+
+  return std::make_pair(std::make_pair(GNew, BM),
+                        std::make_pair(First, NodeIndex));
+}
+
+/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
+///  and collapses PathDiagosticPieces that are expanded by macros.
+static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
+  typedef std::vector<std::pair<PathDiagnosticMacroPiece*, SourceLocation> >
+          MacroStackTy;
+
+  typedef std::vector<PathDiagnosticPiece*>
+          PiecesTy;
+
+  MacroStackTy MacroStack;
+  PiecesTy Pieces;
+
+  for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
+    // Get the location of the PathDiagnosticPiece.
+    const FullSourceLoc Loc = I->getLocation().asLocation();
+
+    // Determine the instantiation location, which is the location we group
+    // related PathDiagnosticPieces.
+    SourceLocation InstantiationLoc = Loc.isMacroID() ?
+                                      SM.getInstantiationLoc(Loc) :
+                                      SourceLocation();
+
+    if (Loc.isFileID()) {
+      MacroStack.clear();
+      Pieces.push_back(&*I);
+      continue;
+    }
+
+    assert(Loc.isMacroID());
+
+    // Is the PathDiagnosticPiece within the same macro group?
+    if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
+      MacroStack.back().first->push_back(&*I);
+      continue;
+    }
+
+    // We aren't in the same group.  Are we descending into a new macro
+    // or are part of an old one?
+    PathDiagnosticMacroPiece *MacroGroup = 0;
+
+    SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
+                                          SM.getInstantiationLoc(Loc) :
+                                          SourceLocation();
+
+    // Walk the entire macro stack.
+    while (!MacroStack.empty()) {
+      if (InstantiationLoc == MacroStack.back().second) {
+        MacroGroup = MacroStack.back().first;
+        break;
+      }
+
+      if (ParentInstantiationLoc == MacroStack.back().second) {
+        MacroGroup = MacroStack.back().first;
+        break;
+      }
+
+      MacroStack.pop_back();
+    }
+
+    if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
+      // Create a new macro group and add it to the stack.
+      PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc);
+
+      if (MacroGroup)
+        MacroGroup->push_back(NewGroup);
+      else {
+        assert(InstantiationLoc.isFileID());
+        Pieces.push_back(NewGroup);
+      }
+
+      MacroGroup = NewGroup;
+      MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
+    }
+
+    // Finally, add the PathDiagnosticPiece to the group.
+    MacroGroup->push_back(&*I);
+  }
+
+  // Now take the pieces and construct a new PathDiagnostic.
+  PD.resetPath(false);
+
+  for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) {
+    if (PathDiagnosticMacroPiece *MP=dyn_cast<PathDiagnosticMacroPiece>(*I))
+      if (!MP->containsEvent()) {
+        delete MP;
+        continue;
+      }
+
+    PD.push_back(*I);
+  }
+}
+
+void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
+                        llvm::SmallVectorImpl<BugReport *> &bugReports) {
+
+  assert(!bugReports.empty());
+  llvm::SmallVector<const ExplodedNode *, 10> errorNodes;
+  for (llvm::SmallVectorImpl<BugReport*>::iterator I = bugReports.begin(),
+    E = bugReports.end(); I != E; ++I) {
+      errorNodes.push_back((*I)->getErrorNode());
+  }
+
+  // Construct a new graph that contains only a single path from the error
+  // node to a root.
+  const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
+  std::pair<ExplodedNode*, unsigned> >&
+    GPair = MakeReportGraph(&getGraph(), errorNodes);
+
+  // Find the BugReport with the original location.
+  assert(GPair.second.second < bugReports.size());
+  BugReport *R = bugReports[GPair.second.second];
+  assert(R && "No original report found for sliced graph.");
+
+  llvm::OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first);
+  llvm::OwningPtr<NodeBackMap> BackMap(GPair.first.second);
+  const ExplodedNode *N = GPair.second.first;
+
+  // Start building the path diagnostic...
+  PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient());
+
+  if (PathDiagnosticPiece* Piece = R->getEndPath(PDB, N))
+    PD.push_back(Piece);
+  else
+    return;
+
+  // Register node visitors.
+  R->registerInitialVisitors(PDB, N);
+  bugreporter::registerNilReceiverVisitor(PDB);
+
+  switch (PDB.getGenerationScheme()) {
+    case PathDiagnosticClient::Extensive:
+      GenerateExtensivePathDiagnostic(PD, PDB, N);
+      break;
+    case PathDiagnosticClient::Minimal:
+      GenerateMinimalPathDiagnostic(PD, PDB, N);
+      break;
+  }
+}
+
+void BugReporter::Register(BugType *BT) {
+  BugTypes = F.add(BugTypes, BT);
+}
+
+void BugReporter::EmitReport(BugReport* R) {
+  // Compute the bug report's hash to determine its equivalence class.
+  llvm::FoldingSetNodeID ID;
+  R->Profile(ID);
+
+  // Lookup the equivance class.  If there isn't one, create it.
+  BugType& BT = R->getBugType();
+  Register(&BT);
+  void *InsertPos;
+  BugReportEquivClass* EQ = BT.EQClasses.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!EQ) {
+    EQ = new BugReportEquivClass(R);
+    BT.EQClasses.InsertNode(EQ, InsertPos);
+  }
+  else
+    EQ->AddReport(R);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Emitting reports in equivalence classes.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct FRIEC_WLItem {
+  const ExplodedNode *N;
+  ExplodedNode::const_succ_iterator I, E;
+  
+  FRIEC_WLItem(const ExplodedNode *n)
+  : N(n), I(N->succ_begin()), E(N->succ_end()) {}
+};  
+}
+
+static BugReport *
+FindReportInEquivalenceClass(BugReportEquivClass& EQ,
+                             llvm::SmallVectorImpl<BugReport*> &bugReports) {
+
+  BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
+  assert(I != E);
+  BugReport *R = *I;
+  BugType& BT = R->getBugType();
+
+  // If we don't need to suppress any of the nodes because they are
+  // post-dominated by a sink, simply add all the nodes in the equivalence class
+  // to 'Nodes'.  Any of the reports will serve as a "representative" report.
+  if (!BT.isSuppressOnSink()) {
+    for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) {
+      const ExplodedNode* N = I->getErrorNode();
+      if (N) {
+        R = *I;
+        bugReports.push_back(R);
+      }
+    }
+    return R;
+  }
+
+  // For bug reports that should be suppressed when all paths are post-dominated
+  // by a sink node, iterate through the reports in the equivalence class
+  // until we find one that isn't post-dominated (if one exists).  We use a
+  // DFS traversal of the ExplodedGraph to find a non-sink node.  We could write
+  // this as a recursive function, but we don't want to risk blowing out the
+  // stack for very long paths.
+  BugReport *exampleReport = 0;
+
+  for (; I != E; ++I) {
+    R = *I;
+    const ExplodedNode *errorNode = R->getErrorNode();
+
+    if (!errorNode)
+      continue;
+    if (errorNode->isSink()) {
+      assert(false &&
+           "BugType::isSuppressSink() should not be 'true' for sink end nodes");
+      return 0;
+    }
+    // No successors?  By definition this nodes isn't post-dominated by a sink.
+    if (errorNode->succ_empty()) {
+      bugReports.push_back(R);
+      if (!exampleReport)
+        exampleReport = R;
+      continue;
+    }
+
+    // At this point we know that 'N' is not a sink and it has at least one
+    // successor.  Use a DFS worklist to find a non-sink end-of-path node.    
+    typedef FRIEC_WLItem WLItem;
+    typedef llvm::SmallVector<WLItem, 10> DFSWorkList;
+    llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
+    
+    DFSWorkList WL;
+    WL.push_back(errorNode);
+    Visited[errorNode] = 1;
+    
+    while (!WL.empty()) {
+      WLItem &WI = WL.back();
+      assert(!WI.N->succ_empty());
+            
+      for (; WI.I != WI.E; ++WI.I) {
+        const ExplodedNode *Succ = *WI.I;        
+        // End-of-path node?
+        if (Succ->succ_empty()) {
+          // If we found an end-of-path node that is not a sink.
+          if (!Succ->isSink()) {
+            bugReports.push_back(R);
+            if (!exampleReport)
+              exampleReport = R;
+            WL.clear();
+            break;
+          }
+          // Found a sink?  Continue on to the next successor.
+          continue;
+        }
+        // Mark the successor as visited.  If it hasn't been explored,
+        // enqueue it to the DFS worklist.
+        unsigned &mark = Visited[Succ];
+        if (!mark) {
+          mark = 1;
+          WL.push_back(Succ);
+          break;
+        }
+      }
+
+      // The worklist may have been cleared at this point.  First
+      // check if it is empty before checking the last item.
+      if (!WL.empty() && &WL.back() == &WI)
+        WL.pop_back();
+    }
+  }
+
+  // ExampleReport will be NULL if all the nodes in the equivalence class
+  // were post-dominated by sinks.
+  return exampleReport;
+}
+
+//===----------------------------------------------------------------------===//
+// DiagnosticCache.  This is a hack to cache analyzer diagnostics.  It
+// uses global state, which eventually should go elsewhere.
+//===----------------------------------------------------------------------===//
+namespace {
+class DiagCacheItem : public llvm::FoldingSetNode {
+  llvm::FoldingSetNodeID ID;
+public:
+  DiagCacheItem(BugReport *R, PathDiagnostic *PD) {
+    ID.AddString(R->getBugType().getName());
+    ID.AddString(R->getBugType().getCategory());
+    ID.AddString(R->getDescription());
+    ID.AddInteger(R->getLocation().getRawEncoding());
+    PD->Profile(ID);    
+  }
+  
+  void Profile(llvm::FoldingSetNodeID &id) {
+    id = ID;
+  }
+  
+  llvm::FoldingSetNodeID &getID() { return ID; }
+};
+}
+
+static bool IsCachedDiagnostic(BugReport *R, PathDiagnostic *PD) {
+  // FIXME: Eventually this diagnostic cache should reside in something
+  // like AnalysisManager instead of being a static variable.  This is
+  // really unsafe in the long term.
+  typedef llvm::FoldingSet<DiagCacheItem> DiagnosticCache;
+  static DiagnosticCache DC;
+  
+  void *InsertPos;
+  DiagCacheItem *Item = new DiagCacheItem(R, PD);
+  
+  if (DC.FindNodeOrInsertPos(Item->getID(), InsertPos)) {
+    delete Item;
+    return true;
+  }
+  
+  DC.InsertNode(Item, InsertPos);
+  return false;
+}
+
+void BugReporter::FlushReport(BugReportEquivClass& EQ) {
+  llvm::SmallVector<BugReport*, 10> bugReports;
+  BugReport *exampleReport = FindReportInEquivalenceClass(EQ, bugReports);
+  if (!exampleReport)
+    return;
+  
+  PathDiagnosticClient* PD = getPathDiagnosticClient();
+
+  // FIXME: Make sure we use the 'R' for the path that was actually used.
+  // Probably doesn't make a difference in practice.
+  BugType& BT = exampleReport->getBugType();
+
+  llvm::OwningPtr<PathDiagnostic>
+    D(new PathDiagnostic(exampleReport->getBugType().getName(),
+                         !PD || PD->useVerboseDescription()
+                         ? exampleReport->getDescription() 
+                         : exampleReport->getShortDescription(),
+                         BT.getCategory()));
+
+  if (!bugReports.empty())
+    GeneratePathDiagnostic(*D.get(), bugReports);
+
+  if (IsCachedDiagnostic(exampleReport, D.get()))
+    return;
+  
+  // Get the meta data.
+  std::pair<const char**, const char**> Meta =
+    exampleReport->getExtraDescriptiveText();
+  for (const char** s = Meta.first; s != Meta.second; ++s)
+    D->addMeta(*s);
+
+  // Emit a summary diagnostic to the regular Diagnostics engine.
+  BugReport::ranges_iterator Beg, End;
+  llvm::tie(Beg, End) = exampleReport->getRanges();
+  Diagnostic &Diag = getDiagnostic();
+  FullSourceLoc L(exampleReport->getLocation(), getSourceManager());
+  
+  // Search the description for '%', as that will be interpretted as a
+  // format character by FormatDiagnostics.
+  llvm::StringRef desc = exampleReport->getShortDescription();
+  unsigned ErrorDiag;
+  {
+    llvm::SmallString<512> TmpStr;
+    llvm::raw_svector_ostream Out(TmpStr);
+    for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
+      if (*I == '%')
+        Out << "%%";
+      else
+        Out << *I;
+    
+    Out.flush();
+    ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr);
+  }        
+
+  {
+    DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag);
+    for (BugReport::ranges_iterator I = Beg; I != End; ++I)
+      diagBuilder << *I;
+  }
+
+  // Emit a full diagnostic for the path if we have a PathDiagnosticClient.
+  if (!PD)
+    return;
+
+  if (D->empty()) {
+    PathDiagnosticPiece* piece =
+      new PathDiagnosticEventPiece(L, exampleReport->getDescription());
+
+    for ( ; Beg != End; ++Beg) piece->addRange(*Beg);
+    D->push_back(piece);
+  }
+
+  PD->HandlePathDiagnostic(D.take());
+}
+
+void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str,
+                                  SourceLocation Loc,
+                                  SourceRange* RBeg, unsigned NumRanges) {
+  EmitBasicReport(name, "", str, Loc, RBeg, NumRanges);
+}
+
+void BugReporter::EmitBasicReport(llvm::StringRef name,
+                                  llvm::StringRef category,
+                                  llvm::StringRef str, SourceLocation Loc,
+                                  SourceRange* RBeg, unsigned NumRanges) {
+
+  // 'BT' will be owned by BugReporter as soon as we call 'EmitReport'.
+  BugType *BT = new BugType(name, category);
+  FullSourceLoc L = getContext().getFullLoc(Loc);
+  RangedBugReport *R = new DiagBugReport(*BT, str, L);
+  for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg);
+  EmitReport(R);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/BugReporterVisitors.cpp b/lib/StaticAnalyzer/EntoSA/BugReporterVisitors.cpp
new file mode 100644 (file)
index 0000000..91d7275
--- /dev/null
@@ -0,0 +1,457 @@
+// BugReporterVisitors.cpp - Helpers for reporting bugs -----------*- 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 a set of BugReporter "visitors" which can be used to
+//  enhance the diagnostics reported for a bug.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
+  // Pattern match for a few useful cases (do something smarter later):
+  //   a[0], p->f, *p
+  const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+
+  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
+    if (U->getOpcode() == UO_Deref)
+      return U->getSubExpr()->IgnoreParenCasts();
+  }
+  else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
+    return ME->getBase()->IgnoreParenCasts();
+  }
+  else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
+    // Retrieve the base for arrays since BasicStoreManager doesn't know how
+    // to reason about them.
+    return AE->getBase();
+  }
+
+  return NULL;
+}
+
+const Stmt *bugreporter::GetDenomExpr(const ExplodedNode *N) {
+  const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
+  if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
+    return BE->getRHS();
+  return NULL;
+}
+
+const Stmt *bugreporter::GetCalleeExpr(const ExplodedNode *N) {
+  // Callee is checked as a PreVisit to the CallExpr.
+  const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
+  if (const CallExpr *CE = dyn_cast<CallExpr>(S))
+    return CE->getCallee();
+  return NULL;
+}
+
+const Stmt *bugreporter::GetRetValExpr(const ExplodedNode *N) {
+  const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
+  if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S))
+    return RS->getRetValue();
+  return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Definitions for bug reporter visitors.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class FindLastStoreBRVisitor : public BugReporterVisitor {
+  const MemRegion *R;
+  SVal V;
+  bool satisfied;
+  const ExplodedNode *StoreSite;
+public:
+  FindLastStoreBRVisitor(SVal v, const MemRegion *r)
+  : R(r), V(v), satisfied(false), StoreSite(0) {}
+
+  virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+    static int tag = 0;
+    ID.AddPointer(&tag);
+    ID.AddPointer(R);
+    ID.Add(V);
+  }
+
+  PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
+                                 const ExplodedNode *PrevN,
+                                 BugReporterContext& BRC) {
+
+    if (satisfied)
+      return NULL;
+
+    if (!StoreSite) {
+      const ExplodedNode *Node = N, *Last = NULL;
+
+      for ( ; Node ; Last = Node, Node = Node->getFirstPred()) {
+
+        if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+          if (const PostStmt *P = Node->getLocationAs<PostStmt>())
+            if (const DeclStmt *DS = P->getStmtAs<DeclStmt>())
+              if (DS->getSingleDecl() == VR->getDecl()) {
+                Last = Node;
+                break;
+              }
+        }
+
+        if (Node->getState()->getSVal(R) != V)
+          break;
+      }
+
+      if (!Node || !Last) {
+        satisfied = true;
+        return NULL;
+      }
+
+      StoreSite = Last;
+    }
+
+    if (StoreSite != N)
+      return NULL;
+
+    satisfied = true;
+    llvm::SmallString<256> sbuf;
+    llvm::raw_svector_ostream os(sbuf);
+
+    if (const PostStmt *PS = N->getLocationAs<PostStmt>()) {
+      if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
+
+        if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+          os << "Variable '" << VR->getDecl() << "' ";
+        }
+        else
+          return NULL;
+
+        if (isa<loc::ConcreteInt>(V)) {
+          bool b = false;
+          if (R->isBoundable()) {
+            if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+              if (TR->getValueType()->isObjCObjectPointerType()) {
+                os << "initialized to nil";
+                b = true;
+              }
+            }
+          }
+
+          if (!b)
+            os << "initialized to a null pointer value";
+        }
+        else if (isa<nonloc::ConcreteInt>(V)) {
+          os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
+        }
+        else if (V.isUndef()) {
+          if (isa<VarRegion>(R)) {
+            const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+            if (VD->getInit())
+              os << "initialized to a garbage value";
+            else
+              os << "declared without an initial value";
+          }
+        }
+      }
+    }
+
+    if (os.str().empty()) {
+      if (isa<loc::ConcreteInt>(V)) {
+        bool b = false;
+        if (R->isBoundable()) {
+          if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+            if (TR->getValueType()->isObjCObjectPointerType()) {
+              os << "nil object reference stored to ";
+              b = true;
+            }
+          }
+        }
+
+        if (!b)
+          os << "Null pointer value stored to ";
+      }
+      else if (V.isUndef()) {
+        os << "Uninitialized value stored to ";
+      }
+      else if (isa<nonloc::ConcreteInt>(V)) {
+        os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
+           << " is assigned to ";
+      }
+      else
+        return NULL;
+
+      if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+        os << '\'' << VR->getDecl() << '\'';
+      }
+      else
+        return NULL;
+    }
+
+    // FIXME: Refactor this into BugReporterContext.
+    const Stmt *S = 0;
+    ProgramPoint P = N->getLocation();
+
+    if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+      const CFGBlock *BSrc = BE->getSrc();
+      S = BSrc->getTerminatorCondition();
+    }
+    else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+      S = PS->getStmt();
+    }
+
+    if (!S)
+      return NULL;
+
+    // Construct a new PathDiagnosticPiece.
+    PathDiagnosticLocation L(S, BRC.getSourceManager());
+    return new PathDiagnosticEventPiece(L, os.str());
+  }
+};
+
+
+static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
+                                  SVal V) {
+  BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+}
+
+class TrackConstraintBRVisitor : public BugReporterVisitor {
+  DefinedSVal Constraint;
+  const bool Assumption;
+  bool isSatisfied;
+public:
+  TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
+  : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    static int tag = 0;
+    ID.AddPointer(&tag);
+    ID.AddBoolean(Assumption);
+    ID.Add(Constraint);
+  }
+
+  PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
+                                 const ExplodedNode *PrevN,
+                                 BugReporterContext& BRC) {
+    if (isSatisfied)
+      return NULL;
+
+    // Check if in the previous state it was feasible for this constraint
+    // to *not* be true.
+    if (PrevN->getState()->assume(Constraint, !Assumption)) {
+
+      isSatisfied = true;
+
+      // As a sanity check, make sure that the negation of the constraint
+      // was infeasible in the current state.  If it is feasible, we somehow
+      // missed the transition point.
+      if (N->getState()->assume(Constraint, !Assumption))
+        return NULL;
+
+      // We found the transition point for the constraint.  We now need to
+      // pretty-print the constraint. (work-in-progress)
+      std::string sbuf;
+      llvm::raw_string_ostream os(sbuf);
+
+      if (isa<Loc>(Constraint)) {
+        os << "Assuming pointer value is ";
+        os << (Assumption ? "non-null" : "null");
+      }
+
+      if (os.str().empty())
+        return NULL;
+
+      // FIXME: Refactor this into BugReporterContext.
+      const Stmt *S = 0;
+      ProgramPoint P = N->getLocation();
+
+      if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+        const CFGBlock *BSrc = BE->getSrc();
+        S = BSrc->getTerminatorCondition();
+      }
+      else if (PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+        S = PS->getStmt();
+      }
+
+      if (!S)
+        return NULL;
+
+      // Construct a new PathDiagnosticPiece.
+      PathDiagnosticLocation L(S, BRC.getSourceManager());
+      return new PathDiagnosticEventPiece(L, os.str());
+    }
+
+    return NULL;
+  }
+};
+} // end anonymous namespace
+
+static void registerTrackConstraint(BugReporterContext& BRC,
+                                    DefinedSVal Constraint,
+                                    bool Assumption) {
+  BRC.addVisitor(new TrackConstraintBRVisitor(Constraint, Assumption));
+}
+
+void bugreporter::registerTrackNullOrUndefValue(BugReporterContext& BRC,
+                                                const void *data,
+                                                const ExplodedNode* N) {
+
+  const Stmt *S = static_cast<const Stmt*>(data);
+
+  if (!S)
+    return;
+
+  GRStateManager &StateMgr = BRC.getStateManager();
+  const GRState *state = N->getState();
+
+  // Walk through lvalue-to-rvalue conversions.  
+  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
+    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+      const VarRegion *R =
+        StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
+
+      // What did we load?
+      SVal V = state->getSVal(loc::MemRegionVal(R));
+
+      if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
+          || V.isUndef()) {
+        ::registerFindLastStore(BRC, R, V);
+      }
+    }
+  }
+
+  SVal V = state->getSValAsScalarOrLoc(S);
+
+  // Uncomment this to find cases where we aren't properly getting the
+  // base value that was dereferenced.
+  // assert(!V.isUnknownOrUndef());
+
+  // Is it a symbolic value?
+  if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
+    const SubRegion *R = cast<SubRegion>(L->getRegion());
+    while (R && !isa<SymbolicRegion>(R)) {
+      R = dyn_cast<SubRegion>(R->getSuperRegion());
+    }
+
+    if (R) {
+      assert(isa<SymbolicRegion>(R));
+      registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
+    }
+  }
+}
+
+void bugreporter::registerFindLastStore(BugReporterContext& BRC,
+                                        const void *data,
+                                        const ExplodedNode* N) {
+
+  const MemRegion *R = static_cast<const MemRegion*>(data);
+
+  if (!R)
+    return;
+
+  const GRState *state = N->getState();
+  SVal V = state->getSVal(R);
+
+  if (V.isUnknown())
+    return;
+
+  BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
+}
+
+
+namespace {
+class NilReceiverVisitor : public BugReporterVisitor {
+public:
+  NilReceiverVisitor() {}
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    static int x = 0;
+    ID.AddPointer(&x);
+  }
+
+  PathDiagnosticPiece* VisitNode(const ExplodedNode *N,
+                                 const ExplodedNode *PrevN,
+                                 BugReporterContext& BRC) {
+
+    const PostStmt *P = N->getLocationAs<PostStmt>();
+    if (!P)
+      return 0;
+    const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
+    if (!ME)
+      return 0;
+    const Expr *Receiver = ME->getInstanceReceiver();
+    if (!Receiver)
+      return 0;
+    const GRState *state = N->getState();
+    const SVal &V = state->getSVal(Receiver);
+    const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
+    if (!DV)
+      return 0;
+    state = state->assume(*DV, true);
+    if (state)
+      return 0;
+
+    // The receiver was nil, and hence the method was skipped.
+    // Register a BugReporterVisitor to issue a message telling us how
+    // the receiver was null.
+    bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N);
+    // Issue a message saying that the method was skipped.
+    PathDiagnosticLocation L(Receiver, BRC.getSourceManager());
+    return new PathDiagnosticEventPiece(L, "No method actually called "
+                                           "because the receiver is nil");
+  }
+};
+} // end anonymous namespace
+
+void bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) {
+  BRC.addVisitor(new NilReceiverVisitor());
+}
+
+// Registers every VarDecl inside a Stmt with a last store vistor.
+void bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC,
+                                                   const void *stmt,
+                                                   const ExplodedNode *N) {
+  const Stmt *S = static_cast<const Stmt *>(stmt);
+
+  std::deque<const Stmt *> WorkList;
+
+  WorkList.push_back(S);
+
+  while (!WorkList.empty()) {
+    const Stmt *Head = WorkList.front();
+    WorkList.pop_front();
+
+    GRStateManager &StateMgr = BRC.getStateManager();
+    const GRState *state = N->getState();
+
+    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Head)) {
+      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+        const VarRegion *R =
+        StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
+
+        // What did we load?
+        SVal V = state->getSVal(S);
+
+        if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
+          ::registerFindLastStore(BRC, R, V);
+        }
+      }
+    }
+
+    for (Stmt::const_child_iterator I = Head->child_begin();
+        I != Head->child_end(); ++I)
+      WorkList.push_back(*I);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/CFRefCount.cpp b/lib/StaticAnalyzer/EntoSA/CFRefCount.cpp
new file mode 100644 (file)
index 0000000..5fd223c
--- /dev/null
@@ -0,0 +1,3500 @@
+// CFRefCount.cpp - Transfer functions for tracking simple 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 the methods for CFRefCount, which implements
+//  a reference count checker for Core Foundation (Mac OS X).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include <stdarg.h>
+
+using namespace clang;
+using namespace ento;
+using llvm::StringRef;
+using llvm::StrInStrNoCase;
+
+namespace {
+class InstanceReceiver {
+  const ObjCMessageExpr *ME;
+  const LocationContext *LC;
+public:
+  InstanceReceiver(const ObjCMessageExpr *me = 0,
+                   const LocationContext *lc = 0) : ME(me), LC(lc) {}
+
+  bool isValid() const {
+    return ME && ME->isInstanceMessage();
+  }
+  operator bool() const {
+    return isValid();
+  }
+
+  SVal getSValAsScalarOrLoc(const GRState *state) {
+    assert(isValid());
+    // We have an expression for the receiver?  Fetch the value
+    // of that expression.
+    if (const Expr *Ex = ME->getInstanceReceiver())
+      return state->getSValAsScalarOrLoc(Ex);
+
+    // Otherwise we are sending a message to super.  In this case the
+    // object reference is the same as 'self'.
+    if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl())
+      return state->getSVal(state->getRegion(SelfDecl, LC));
+
+    return UnknownVal();
+  }
+
+  SourceRange getSourceRange() const {
+    assert(isValid());
+    if (const Expr *Ex = ME->getInstanceReceiver())
+      return Ex->getSourceRange();
+
+    // Otherwise we are sending a message to super.
+    SourceLocation L = ME->getSuperLoc();
+    assert(L.isValid());
+    return SourceRange(L, L);
+  }
+};
+}
+
+static const ObjCMethodDecl*
+ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
+  const ObjCInterfaceDecl *ID = MD->getClassInterface();
+
+  return MD->isInstanceMethod()
+         ? ID->lookupInstanceMethod(MD->getSelector())
+         : ID->lookupClassMethod(MD->getSelector());
+}
+
+namespace {
+class GenericNodeBuilder {
+  StmtNodeBuilder *SNB;
+  const Stmt *S;
+  const void *tag;
+  EndPathNodeBuilder *ENB;
+public:
+  GenericNodeBuilder(StmtNodeBuilder &snb, const Stmt *s,
+                     const void *t)
+  : SNB(&snb), S(s), tag(t), ENB(0) {}
+
+  GenericNodeBuilder(EndPathNodeBuilder &enb)
+  : SNB(0), S(0), tag(0), ENB(&enb) {}
+
+  ExplodedNode *MakeNode(const GRState *state, ExplodedNode *Pred) {
+    if (SNB)
+      return SNB->generateNode(PostStmt(S, Pred->getLocationContext(), tag),
+                               state, Pred);
+
+    assert(ENB);
+    return ENB->generateNode(state, Pred);
+  }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Primitives used for constructing summaries for function/method calls.
+//===----------------------------------------------------------------------===//
+
+/// ArgEffect is used to summarize a function/method call's effect on a
+/// particular argument.
+enum ArgEffect { Autorelease, Dealloc, DecRef, DecRefMsg, DoNothing,
+                 DoNothingByRef, IncRefMsg, IncRef, MakeCollectable, MayEscape,
+                 NewAutoreleasePool, SelfOwn, StopTracking };
+
+namespace llvm {
+template <> struct FoldingSetTrait<ArgEffect> {
+static inline void Profile(const ArgEffect X, FoldingSetNodeID& ID) {
+  ID.AddInteger((unsigned) X);
+}
+};
+} // end llvm namespace
+
+/// ArgEffects summarizes the effects of a function/method call on all of
+/// its arguments.
+typedef llvm::ImmutableMap<unsigned,ArgEffect> ArgEffects;
+
+namespace {
+
+///  RetEffect is used to summarize a function/method call's behavior with
+///  respect to its return value.
+class RetEffect {
+public:
+  enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
+              NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
+              OwnedWhenTrackedReceiver };
+
+  enum ObjKind { CF, ObjC, AnyObj };
+
+private:
+  Kind K;
+  ObjKind O;
+  unsigned index;
+
+  RetEffect(Kind k, unsigned idx = 0) : K(k), O(AnyObj), index(idx) {}
+  RetEffect(Kind k, ObjKind o) : K(k), O(o), index(0) {}
+
+public:
+  Kind getKind() const { return K; }
+
+  ObjKind getObjKind() const { return O; }
+
+  unsigned getIndex() const {
+    assert(getKind() == Alias);
+    return index;
+  }
+
+  bool isOwned() const {
+    return K == OwnedSymbol || K == OwnedAllocatedSymbol ||
+           K == OwnedWhenTrackedReceiver;
+  }
+
+  static RetEffect MakeOwnedWhenTrackedReceiver() {
+    return RetEffect(OwnedWhenTrackedReceiver, ObjC);
+  }
+
+  static RetEffect MakeAlias(unsigned Idx) {
+    return RetEffect(Alias, Idx);
+  }
+  static RetEffect MakeReceiverAlias() {
+    return RetEffect(ReceiverAlias);
+  }
+  static RetEffect MakeOwned(ObjKind o, bool isAllocated = false) {
+    return RetEffect(isAllocated ? OwnedAllocatedSymbol : OwnedSymbol, o);
+  }
+  static RetEffect MakeNotOwned(ObjKind o) {
+    return RetEffect(NotOwnedSymbol, o);
+  }
+  static RetEffect MakeGCNotOwned() {
+    return RetEffect(GCNotOwnedSymbol, ObjC);
+  }
+
+  static RetEffect MakeNoRet() {
+    return RetEffect(NoRet);
+  }
+};
+
+//===----------------------------------------------------------------------===//
+// Reference-counting logic (typestate + counts).
+//===----------------------------------------------------------------------===//
+
+class RefVal {
+public:
+  enum Kind {
+    Owned = 0, // Owning reference.
+    NotOwned,  // Reference is not owned by still valid (not freed).
+    Released,  // Object has been released.
+    ReturnedOwned, // Returned object passes ownership to caller.
+    ReturnedNotOwned, // Return object does not pass ownership to caller.
+    ERROR_START,
+    ErrorDeallocNotOwned, // -dealloc called on non-owned object.
+    ErrorDeallocGC, // Calling -dealloc with GC enabled.
+    ErrorUseAfterRelease, // Object used after released.
+    ErrorReleaseNotOwned, // Release of an object that was not owned.
+    ERROR_LEAK_START,
+    ErrorLeak,  // A memory leak due to excessive reference counts.
+    ErrorLeakReturned, // A memory leak due to the returning method not having
+                       // the correct naming conventions.
+    ErrorGCLeakReturned,
+    ErrorOverAutorelease,
+    ErrorReturnedNotOwned
+  };
+
+private:
+  Kind kind;
+  RetEffect::ObjKind okind;
+  unsigned Cnt;
+  unsigned ACnt;
+  QualType T;
+
+  RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
+  : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
+
+public:
+  Kind getKind() const { return kind; }
+
+  RetEffect::ObjKind getObjKind() const { return okind; }
+
+  unsigned getCount() const { return Cnt; }
+  unsigned getAutoreleaseCount() const { return ACnt; }
+  unsigned getCombinedCounts() const { return Cnt + ACnt; }
+  void clearCounts() { Cnt = 0; ACnt = 0; }
+  void setCount(unsigned i) { Cnt = i; }
+  void setAutoreleaseCount(unsigned i) { ACnt = i; }
+
+  QualType getType() const { return T; }
+
+  bool isOwned() const {
+    return getKind() == Owned;
+  }
+
+  bool isNotOwned() const {
+    return getKind() == NotOwned;
+  }
+
+  bool isReturnedOwned() const {
+    return getKind() == ReturnedOwned;
+  }
+
+  bool isReturnedNotOwned() const {
+    return getKind() == ReturnedNotOwned;
+  }
+
+  static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
+                          unsigned Count = 1) {
+    return RefVal(Owned, o, Count, 0, t);
+  }
+
+  static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
+                             unsigned Count = 0) {
+    return RefVal(NotOwned, o, Count, 0, t);
+  }
+
+  // Comparison, profiling, and pretty-printing.
+
+  bool operator==(const RefVal& X) const {
+    return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
+  }
+
+  RefVal operator-(size_t i) const {
+    return RefVal(getKind(), getObjKind(), getCount() - i,
+                  getAutoreleaseCount(), getType());
+  }
+
+  RefVal operator+(size_t i) const {
+    return RefVal(getKind(), getObjKind(), getCount() + i,
+                  getAutoreleaseCount(), getType());
+  }
+
+  RefVal operator^(Kind k) const {
+    return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
+                  getType());
+  }
+
+  RefVal autorelease() const {
+    return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
+                  getType());
+  }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    ID.AddInteger((unsigned) kind);
+    ID.AddInteger(Cnt);
+    ID.AddInteger(ACnt);
+    ID.Add(T);
+  }
+
+  void print(llvm::raw_ostream& Out) const;
+};
+
+void RefVal::print(llvm::raw_ostream& Out) const {
+  if (!T.isNull())
+    Out << "Tracked Type:" << T.getAsString() << '\n';
+
+  switch (getKind()) {
+    default: assert(false);
+    case Owned: {
+      Out << "Owned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+
+    case NotOwned: {
+      Out << "NotOwned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+
+    case ReturnedOwned: {
+      Out << "ReturnedOwned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+
+    case ReturnedNotOwned: {
+      Out << "ReturnedNotOwned";
+      unsigned cnt = getCount();
+      if (cnt) Out << " (+ " << cnt << ")";
+      break;
+    }
+
+    case Released:
+      Out << "Released";
+      break;
+
+    case ErrorDeallocGC:
+      Out << "-dealloc (GC)";
+      break;
+
+    case ErrorDeallocNotOwned:
+      Out << "-dealloc (not-owned)";
+      break;
+
+    case ErrorLeak:
+      Out << "Leaked";
+      break;
+
+    case ErrorLeakReturned:
+      Out << "Leaked (Bad naming)";
+      break;
+
+    case ErrorGCLeakReturned:
+      Out << "Leaked (GC-ed at return)";
+      break;
+
+    case ErrorUseAfterRelease:
+      Out << "Use-After-Release [ERROR]";
+      break;
+
+    case ErrorReleaseNotOwned:
+      Out << "Release of Not-Owned [ERROR]";
+      break;
+
+    case RefVal::ErrorOverAutorelease:
+      Out << "Over autoreleased";
+      break;
+
+    case RefVal::ErrorReturnedNotOwned:
+      Out << "Non-owned object returned instead of owned";
+      break;
+  }
+
+  if (ACnt) {
+    Out << " [ARC +" << ACnt << ']';
+  }
+}
+} //end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RefBindings - State used to track object reference counts.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
+
+namespace clang {
+namespace ento {
+  template<>
+  struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
+    static void* GDMIndex() {
+      static int RefBIndex = 0;
+      return &RefBIndex;
+    }
+  };
+}
+}
+
+//===----------------------------------------------------------------------===//
+// Summaries
+//===----------------------------------------------------------------------===//
+
+namespace {
+class RetainSummary {
+  /// Args - an ordered vector of (index, ArgEffect) pairs, where index
+  ///  specifies the argument (starting from 0).  This can be sparsely
+  ///  populated; arguments with no entry in Args use 'DefaultArgEffect'.
+  ArgEffects Args;
+
+  /// DefaultArgEffect - The default ArgEffect to apply to arguments that
+  ///  do not have an entry in Args.
+  ArgEffect   DefaultArgEffect;
+
+  /// Receiver - If this summary applies to an Objective-C message expression,
+  ///  this is the effect applied to the state of the receiver.
+  ArgEffect   Receiver;
+
+  /// Ret - The effect on the return value.  Used to indicate if the
+  ///  function/method call returns a new tracked symbol, returns an
+  ///  alias of one of the arguments in the call, and so on.
+  RetEffect   Ret;
+
+  /// EndPath - Indicates that execution of this method/function should
+  ///  terminate the simulation of a path.
+  bool EndPath;
+
+public:
+  RetainSummary(ArgEffects A, RetEffect R, ArgEffect defaultEff,
+                ArgEffect ReceiverEff, bool endpath = false)
+    : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), Ret(R),
+      EndPath(endpath) {}
+
+  /// getArg - Return the argument effect on the argument specified by
+  ///  idx (starting from 0).
+  ArgEffect getArg(unsigned idx) const {
+    if (const ArgEffect *AE = Args.lookup(idx))
+      return *AE;
+
+    return DefaultArgEffect;
+  }
+
+  /// setDefaultArgEffect - Set the default argument effect.
+  void setDefaultArgEffect(ArgEffect E) {
+    DefaultArgEffect = E;
+  }
+
+  /// getRetEffect - Returns the effect on the return value of the call.
+  RetEffect getRetEffect() const { return Ret; }
+
+  /// setRetEffect - Set the effect of the return value of the call.
+  void setRetEffect(RetEffect E) { Ret = E; }
+
+  /// isEndPath - Returns true if executing the given method/function should
+  ///  terminate the path.
+  bool isEndPath() const { return EndPath; }
+
+  /// getReceiverEffect - Returns the effect on the receiver of the call.
+  ///  This is only meaningful if the summary applies to an ObjCMessageExpr*.
+  ArgEffect getReceiverEffect() const { return Receiver; }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Data structures for constructing summaries.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ObjCSummaryKey {
+  IdentifierInfo* II;
+  Selector S;
+public:
+  ObjCSummaryKey(IdentifierInfo* ii, Selector s)
+    : II(ii), S(s) {}
+
+  ObjCSummaryKey(const ObjCInterfaceDecl* d, Selector s)
+    : II(d ? d->getIdentifier() : 0), S(s) {}
+
+  ObjCSummaryKey(const ObjCInterfaceDecl* d, IdentifierInfo *ii, Selector s)
+    : II(d ? d->getIdentifier() : ii), S(s) {}
+
+  ObjCSummaryKey(Selector s)
+    : II(0), S(s) {}
+
+  IdentifierInfo* getIdentifier() const { return II; }
+  Selector getSelector() const { return S; }
+};
+}
+
+namespace llvm {
+template <> struct DenseMapInfo<ObjCSummaryKey> {
+  static inline ObjCSummaryKey getEmptyKey() {
+    return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
+                          DenseMapInfo<Selector>::getEmptyKey());
+  }
+
+  static inline ObjCSummaryKey getTombstoneKey() {
+    return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
+                          DenseMapInfo<Selector>::getTombstoneKey());
+  }
+
+  static unsigned getHashValue(const ObjCSummaryKey &V) {
+    return (DenseMapInfo<IdentifierInfo*>::getHashValue(V.getIdentifier())
+            & 0x88888888)
+        | (DenseMapInfo<Selector>::getHashValue(V.getSelector())
+            & 0x55555555);
+  }
+
+  static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) {
+    return DenseMapInfo<IdentifierInfo*>::isEqual(LHS.getIdentifier(),
+                                                  RHS.getIdentifier()) &&
+           DenseMapInfo<Selector>::isEqual(LHS.getSelector(),
+                                           RHS.getSelector());
+  }
+
+};
+template <>
+struct isPodLike<ObjCSummaryKey> { static const bool value = true; };
+} // end llvm namespace
+
+namespace {
+class ObjCSummaryCache {
+  typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
+  MapTy M;
+public:
+  ObjCSummaryCache() {}
+
+  RetainSummary* find(const ObjCInterfaceDecl* D, IdentifierInfo *ClsName,
+                Selector S) {
+    // Lookup the method using the decl for the class @interface.  If we
+    // have no decl, lookup using the class name.
+    return D ? find(D, S) : find(ClsName, S);
+  }
+
+  RetainSummary* find(const ObjCInterfaceDecl* D, Selector S) {
+    // Do a lookup with the (D,S) pair.  If we find a match return
+    // the iterator.
+    ObjCSummaryKey K(D, S);
+    MapTy::iterator I = M.find(K);
+
+    if (I != M.end() || !D)
+      return I->second;
+
+    // Walk the super chain.  If we find a hit with a parent, we'll end
+    // up returning that summary.  We actually allow that key (null,S), as
+    // we cache summaries for the null ObjCInterfaceDecl* to allow us to
+    // generate initial summaries without having to worry about NSObject
+    // being declared.
+    // FIXME: We may change this at some point.
+    for (ObjCInterfaceDecl* C=D->getSuperClass() ;; C=C->getSuperClass()) {
+      if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
+        break;
+
+      if (!C)
+        return NULL;
+    }
+
+    // Cache the summary with original key to make the next lookup faster
+    // and return the iterator.
+    RetainSummary *Summ = I->second;
+    M[K] = Summ;
+    return Summ;
+  }
+
+  RetainSummary* find(IdentifierInfo* II, Selector S) {
+    // FIXME: Class method lookup.  Right now we dont' have a good way
+    // of going between IdentifierInfo* and the class hierarchy.
+    MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
+
+    if (I == M.end())
+      I = M.find(ObjCSummaryKey(S));
+
+    return I == M.end() ? NULL : I->second;
+  }
+
+  RetainSummary*& operator[](ObjCSummaryKey K) {
+    return M[K];
+  }
+
+  RetainSummary*& operator[](Selector S) {
+    return M[ ObjCSummaryKey(S) ];
+  }
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Data structures for managing collections of summaries.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class RetainSummaryManager {
+
+  //==-----------------------------------------------------------------==//
+  //  Typedefs.
+  //==-----------------------------------------------------------------==//
+
+  typedef llvm::DenseMap<const FunctionDecl*, RetainSummary*>
+          FuncSummariesTy;
+
+  typedef ObjCSummaryCache ObjCMethodSummariesTy;
+
+  //==-----------------------------------------------------------------==//
+  //  Data.
+  //==-----------------------------------------------------------------==//
+
+  /// Ctx - The ASTContext object for the analyzed ASTs.
+  ASTContext& Ctx;
+
+  /// CFDictionaryCreateII - An IdentifierInfo* representing the indentifier
+  ///  "CFDictionaryCreate".
+  IdentifierInfo* CFDictionaryCreateII;
+
+  /// GCEnabled - Records whether or not the analyzed code runs in GC mode.
+  const bool GCEnabled;
+
+  /// FuncSummaries - A map from FunctionDecls to summaries.
+  FuncSummariesTy FuncSummaries;
+
+  /// ObjCClassMethodSummaries - A map from selectors (for instance methods)
+  ///  to summaries.
+  ObjCMethodSummariesTy ObjCClassMethodSummaries;
+
+  /// ObjCMethodSummaries - A map from selectors to summaries.
+  ObjCMethodSummariesTy ObjCMethodSummaries;
+
+  /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
+  ///  and all other data used by the checker.
+  llvm::BumpPtrAllocator BPAlloc;
+
+  /// AF - A factory for ArgEffects objects.
+  ArgEffects::Factory AF;
+
+  /// ScratchArgs - A holding buffer for construct ArgEffects.
+  ArgEffects ScratchArgs;
+
+  /// ObjCAllocRetE - Default return effect for methods returning Objective-C
+  ///  objects.
+  RetEffect ObjCAllocRetE;
+
+  /// ObjCInitRetE - Default return effect for init methods returning
+  ///   Objective-C objects.
+  RetEffect ObjCInitRetE;
+
+  RetainSummary DefaultSummary;
+  RetainSummary* StopSummary;
+
+  //==-----------------------------------------------------------------==//
+  //  Methods.
+  //==-----------------------------------------------------------------==//
+
+  /// getArgEffects - Returns a persistent ArgEffects object based on the
+  ///  data in ScratchArgs.
+  ArgEffects getArgEffects();
+
+  enum UnaryFuncKind { cfretain, cfrelease, cfmakecollectable };
+
+public:
+  RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
+
+  RetainSummary *getDefaultSummary() {
+    RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+    return new (Summ) RetainSummary(DefaultSummary);
+  }
+
+  RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func);
+
+  RetainSummary* getCFSummaryCreateRule(const FunctionDecl* FD);
+  RetainSummary* getCFSummaryGetRule(const FunctionDecl* FD);
+  RetainSummary* getCFCreateGetRuleSummary(const FunctionDecl* FD, 
+                                           StringRef FName);
+
+  RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+                                      ArgEffect ReceiverEff = DoNothing,
+                                      ArgEffect DefaultEff = MayEscape,
+                                      bool isEndPath = false);
+
+  RetainSummary* getPersistentSummary(RetEffect RE,
+                                      ArgEffect ReceiverEff = DoNothing,
+                                      ArgEffect DefaultEff = MayEscape) {
+    return getPersistentSummary(getArgEffects(), RE, ReceiverEff, DefaultEff);
+  }
+
+  RetainSummary *getPersistentStopSummary() {
+    if (StopSummary)
+      return StopSummary;
+
+    StopSummary = getPersistentSummary(RetEffect::MakeNoRet(),
+                                       StopTracking, StopTracking);
+
+    return StopSummary;
+  }
+
+  RetainSummary *getInitMethodSummary(QualType RetTy);
+
+  void InitializeClassMethodSummaries();
+  void InitializeMethodSummaries();
+private:
+  void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) {
+    ObjCClassMethodSummaries[S] = Summ;
+  }
+
+  void addNSObjectMethSummary(Selector S, RetainSummary *Summ) {
+    ObjCMethodSummaries[S] = Summ;
+  }
+
+  void addClassMethSummary(const char* Cls, const char* nullaryName,
+                           RetainSummary *Summ) {
+    IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
+    Selector S = GetNullarySelector(nullaryName, Ctx);
+    ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ;
+  }
+
+  void addInstMethSummary(const char* Cls, const char* nullaryName,
+                          RetainSummary *Summ) {
+    IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
+    Selector S = GetNullarySelector(nullaryName, Ctx);
+    ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)]  = Summ;
+  }
+
+  Selector generateSelector(va_list argp) {
+    llvm::SmallVector<IdentifierInfo*, 10> II;
+
+    while (const char* s = va_arg(argp, const char*))
+      II.push_back(&Ctx.Idents.get(s));
+
+    return Ctx.Selectors.getSelector(II.size(), &II[0]);
+  }
+
+  void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
+                        RetainSummary* Summ, va_list argp) {
+    Selector S = generateSelector(argp);
+    Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
+  }
+
+  void addInstMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+    va_list argp;
+    va_start(argp, Summ);
+    addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
+    va_end(argp);
+  }
+
+  void addClsMethSummary(const char* Cls, RetainSummary* Summ, ...) {
+    va_list argp;
+    va_start(argp, Summ);
+    addMethodSummary(&Ctx.Idents.get(Cls),ObjCClassMethodSummaries, Summ, argp);
+    va_end(argp);
+  }
+
+  void addClsMethSummary(IdentifierInfo *II, RetainSummary* Summ, ...) {
+    va_list argp;
+    va_start(argp, Summ);
+    addMethodSummary(II, ObjCClassMethodSummaries, Summ, argp);
+    va_end(argp);
+  }
+
+  void addPanicSummary(const char* Cls, ...) {
+    RetainSummary* Summ = getPersistentSummary(AF.getEmptyMap(),
+                                               RetEffect::MakeNoRet(),
+                                               DoNothing,  DoNothing, true);
+    va_list argp;
+    va_start (argp, Cls);
+    addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, argp);
+    va_end(argp);
+  }
+
+public:
+
+  RetainSummaryManager(ASTContext& ctx, bool gcenabled)
+   : Ctx(ctx),
+     CFDictionaryCreateII(&ctx.Idents.get("CFDictionaryCreate")),
+     GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
+     ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned()
+                             : RetEffect::MakeOwned(RetEffect::ObjC, true)),
+     ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned()
+                            : RetEffect::MakeOwnedWhenTrackedReceiver()),
+     DefaultSummary(AF.getEmptyMap() /* per-argument effects (none) */,
+                    RetEffect::MakeNoRet() /* return effect */,
+                    MayEscape, /* default argument effect */
+                    DoNothing /* receiver effect */),
+     StopSummary(0) {
+
+    InitializeClassMethodSummaries();
+    InitializeMethodSummaries();
+  }
+
+  ~RetainSummaryManager();
+
+  RetainSummary* getSummary(const FunctionDecl* FD);
+
+  RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+                                          const GRState *state,
+                                          const LocationContext *LC);
+
+  RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
+                                          const ObjCInterfaceDecl* ID) {
+    return getInstanceMethodSummary(ME->getSelector(), 0,
+                            ID, ME->getMethodDecl(), ME->getType());
+  }
+
+  RetainSummary* getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName,
+                                          const ObjCInterfaceDecl* ID,
+                                          const ObjCMethodDecl *MD,
+                                          QualType RetTy);
+
+  RetainSummary *getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
+                                       const ObjCInterfaceDecl *ID,
+                                       const ObjCMethodDecl *MD,
+                                       QualType RetTy);
+
+  RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
+    ObjCInterfaceDecl *Class = 0;
+    switch (ME->getReceiverKind()) {
+    case ObjCMessageExpr::Class:
+    case ObjCMessageExpr::SuperClass:
+      Class = ME->getReceiverInterface();
+      break;
+
+    case ObjCMessageExpr::Instance:
+    case ObjCMessageExpr::SuperInstance:
+      break;
+    }
+
+    return getClassMethodSummary(ME->getSelector(),
+                                 Class? Class->getIdentifier() : 0,
+                                 Class,
+                                 ME->getMethodDecl(), ME->getType());
+  }
+
+  /// getMethodSummary - This version of getMethodSummary is used to query
+  ///  the summary for the current method being analyzed.
+  RetainSummary *getMethodSummary(const ObjCMethodDecl *MD) {
+    // FIXME: Eventually this should be unneeded.
+    const ObjCInterfaceDecl *ID = MD->getClassInterface();
+    Selector S = MD->getSelector();
+    IdentifierInfo *ClsName = ID->getIdentifier();
+    QualType ResultTy = MD->getResultType();
+
+    // Resolve the method decl last.
+    if (const ObjCMethodDecl *InterfaceMD = ResolveToInterfaceMethodDecl(MD))
+      MD = InterfaceMD;
+
+    if (MD->isInstanceMethod())
+      return getInstanceMethodSummary(S, ClsName, ID, MD, ResultTy);
+    else
+      return getClassMethodSummary(S, ClsName, ID, MD, ResultTy);
+  }
+
+  RetainSummary* getCommonMethodSummary(const ObjCMethodDecl* MD,
+                                        Selector S, QualType RetTy);
+
+  void updateSummaryFromAnnotations(RetainSummary &Summ,
+                                    const ObjCMethodDecl *MD);
+
+  void updateSummaryFromAnnotations(RetainSummary &Summ,
+                                    const FunctionDecl *FD);
+
+  bool isGCEnabled() const { return GCEnabled; }
+
+  RetainSummary *copySummary(RetainSummary *OldSumm) {
+    RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+    new (Summ) RetainSummary(*OldSumm);
+    return Summ;
+  }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Implementation of checker data structures.
+//===----------------------------------------------------------------------===//
+
+RetainSummaryManager::~RetainSummaryManager() {}
+
+ArgEffects RetainSummaryManager::getArgEffects() {
+  ArgEffects AE = ScratchArgs;
+  ScratchArgs = AF.getEmptyMap();
+  return AE;
+}
+
+RetainSummary*
+RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff,
+                                           ArgEffect ReceiverEff,
+                                           ArgEffect DefaultEff,
+                                           bool isEndPath) {
+  // Create the summary and return it.
+  RetainSummary *Summ = (RetainSummary*) BPAlloc.Allocate<RetainSummary>();
+  new (Summ) RetainSummary(AE, RetEff, DefaultEff, ReceiverEff, isEndPath);
+  return Summ;
+}
+
+//===----------------------------------------------------------------------===//
+// Summary creation for functions (largely uses of Core Foundation).
+//===----------------------------------------------------------------------===//
+
+static bool isRetain(const FunctionDecl* FD, StringRef FName) {
+  return FName.endswith("Retain");
+}
+
+static bool isRelease(const FunctionDecl* FD, StringRef FName) {
+  return FName.endswith("Release");
+}
+
+RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
+  // Look up a summary in our cache of FunctionDecls -> Summaries.
+  FuncSummariesTy::iterator I = FuncSummaries.find(FD);
+  if (I != FuncSummaries.end())
+    return I->second;
+
+  // No summary?  Generate one.
+  RetainSummary *S = 0;
+
+  do {
+    // We generate "stop" summaries for implicitly defined functions.
+    if (FD->isImplicit()) {
+      S = getPersistentStopSummary();
+      break;
+    }
+
+    // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
+    // function's type.
+    const FunctionType* FT = FD->getType()->getAs<FunctionType>();
+    const IdentifierInfo *II = FD->getIdentifier();
+    if (!II)
+      break;
+
+    StringRef FName = II->getName();
+
+    // Strip away preceding '_'.  Doing this here will effect all the checks
+    // down below.
+    FName = FName.substr(FName.find_first_not_of('_'));
+
+    // Inspect the result type.
+    QualType RetTy = FT->getResultType();
+
+    // FIXME: This should all be refactored into a chain of "summary lookup"
+    //  filters.
+    assert(ScratchArgs.isEmpty());
+
+    if (FName == "pthread_create") {
+      // Part of: <rdar://problem/7299394>.  This will be addressed
+      // better with IPA.
+      S = getPersistentStopSummary();
+    } else if (FName == "NSMakeCollectable") {
+      // Handle: id NSMakeCollectable(CFTypeRef)
+      S = (RetTy->isObjCIdType())
+          ? getUnarySummary(FT, cfmakecollectable)
+          : getPersistentStopSummary();
+    } else if (FName == "IOBSDNameMatching" ||
+               FName == "IOServiceMatching" ||
+               FName == "IOServiceNameMatching" ||
+               FName == "IORegistryEntryIDMatching" ||
+               FName == "IOOpenFirmwarePathMatching") {
+      // Part of <rdar://problem/6961230>. (IOKit)
+      // This should be addressed using a API table.
+      S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+                               DoNothing, DoNothing);
+    } else if (FName == "IOServiceGetMatchingService" ||
+               FName == "IOServiceGetMatchingServices") {
+      // FIXES: <rdar://problem/6326900>
+      // This should be addressed using a API table.  This strcmp is also
+      // a little gross, but there is no need to super optimize here.
+      ScratchArgs = AF.add(ScratchArgs, 1, DecRef);
+      S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+    } else if (FName == "IOServiceAddNotification" ||
+               FName == "IOServiceAddMatchingNotification") {
+      // Part of <rdar://problem/6961230>. (IOKit)
+      // This should be addressed using a API table.
+      ScratchArgs = AF.add(ScratchArgs, 2, DecRef);
+      S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+    } else if (FName == "CVPixelBufferCreateWithBytes") {
+      // FIXES: <rdar://problem/7283567>
+      // Eventually this can be improved by recognizing that the pixel
+      // buffer passed to CVPixelBufferCreateWithBytes is released via
+      // a callback and doing full IPA to make sure this is done correctly.
+      // FIXME: This function has an out parameter that returns an
+      // allocated object.
+      ScratchArgs = AF.add(ScratchArgs, 7, StopTracking);
+      S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+    } else if (FName == "CGBitmapContextCreateWithData") {
+      // FIXES: <rdar://problem/7358899>
+      // Eventually this can be improved by recognizing that 'releaseInfo'
+      // passed to CGBitmapContextCreateWithData is released via
+      // a callback and doing full IPA to make sure this is done correctly.
+      ScratchArgs = AF.add(ScratchArgs, 8, StopTracking);
+      S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true),
+                               DoNothing, DoNothing);
+    } else if (FName == "CVPixelBufferCreateWithPlanarBytes") {
+      // FIXES: <rdar://problem/7283567>
+      // Eventually this can be improved by recognizing that the pixel
+      // buffer passed to CVPixelBufferCreateWithPlanarBytes is released
+      // via a callback and doing full IPA to make sure this is done
+      // correctly.
+      ScratchArgs = AF.add(ScratchArgs, 12, StopTracking);
+      S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
+    }
+
+    // Did we get a summary?
+    if (S)
+      break;
+
+    // Enable this code once the semantics of NSDeallocateObject are resolved
+    // for GC.  <rdar://problem/6619988>
+#if 0
+    // Handle: NSDeallocateObject(id anObject);
+    // This method does allow 'nil' (although we don't check it now).
+    if (strcmp(FName, "NSDeallocateObject") == 0) {
+      return RetTy == Ctx.VoidTy
+        ? getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, Dealloc)
+        : getPersistentStopSummary();
+    }
+#endif
+
+    if (RetTy->isPointerType()) {
+      // For CoreFoundation ('CF') types.
+      if (cocoa::isRefType(RetTy, "CF", FName)) {
+        if (isRetain(FD, FName))
+          S = getUnarySummary(FT, cfretain);
+        else if (FName.find("MakeCollectable") != StringRef::npos)
+          S = getUnarySummary(FT, cfmakecollectable);
+        else
+          S = getCFCreateGetRuleSummary(FD, FName);
+
+        break;
+      }
+
+      // For CoreGraphics ('CG') types.
+      if (cocoa::isRefType(RetTy, "CG", FName)) {
+        if (isRetain(FD, FName))
+          S = getUnarySummary(FT, cfretain);
+        else
+          S = getCFCreateGetRuleSummary(FD, FName);
+
+        break;
+      }
+
+      // For the Disk Arbitration API (DiskArbitration/DADisk.h)
+      if (cocoa::isRefType(RetTy, "DADisk") ||
+          cocoa::isRefType(RetTy, "DADissenter") ||
+          cocoa::isRefType(RetTy, "DASessionRef")) {
+        S = getCFCreateGetRuleSummary(FD, FName);
+        break;
+      }
+
+      break;
+    }
+
+    // Check for release functions, the only kind of functions that we care
+    // about that don't return a pointer type.
+    if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) {
+      // Test for 'CGCF'.
+      FName = FName.substr(FName.startswith("CGCF") ? 4 : 2);
+
+      if (isRelease(FD, FName))
+        S = getUnarySummary(FT, cfrelease);
+      else {
+        assert (ScratchArgs.isEmpty());
+        // Remaining CoreFoundation and CoreGraphics functions.
+        // We use to assume that they all strictly followed the ownership idiom
+        // and that ownership cannot be transferred.  While this is technically
+        // correct, many methods allow a tracked object to escape.  For example:
+        //
+        //   CFMutableDictionaryRef x = CFDictionaryCreateMutable(...);
+        //   CFDictionaryAddValue(y, key, x);
+        //   CFRelease(x);
+        //   ... it is okay to use 'x' since 'y' has a reference to it
+        //
+        // We handle this and similar cases with the follow heuristic.  If the
+        // function name contains "InsertValue", "SetValue", "AddValue",
+        // "AppendValue", or "SetAttribute", then we assume that arguments may
+        // "escape."  This means that something else holds on to the object,
+        // allowing it be used even after its local retain count drops to 0.
+        ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
+                       StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
+                       StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
+                       StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
+                       StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
+                      ? MayEscape : DoNothing;
+
+        S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
+      }
+    }
+  }
+  while (0);
+
+  if (!S)
+    S = getDefaultSummary();
+
+  // Annotations override defaults.
+  assert(S);
+  updateSummaryFromAnnotations(*S, FD);
+
+  FuncSummaries[FD] = S;
+  return S;
+}
+
+RetainSummary*
+RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD,
+                                                StringRef FName) {
+
+  if (FName.find("Create") != StringRef::npos ||
+      FName.find("Copy") != StringRef::npos)
+    return getCFSummaryCreateRule(FD);
+
+  if (FName.find("Get") != StringRef::npos)
+    return getCFSummaryGetRule(FD);
+
+  return getDefaultSummary();
+}
+
+RetainSummary*
+RetainSummaryManager::getUnarySummary(const FunctionType* FT,
+                                      UnaryFuncKind func) {
+
+  // Sanity check that this is *really* a unary function.  This can
+  // happen if people do weird things.
+  const FunctionProtoType* FTP = dyn_cast<FunctionProtoType>(FT);
+  if (!FTP || FTP->getNumArgs() != 1)
+    return getPersistentStopSummary();
+
+  assert (ScratchArgs.isEmpty());
+
+  switch (func) {
+    case cfretain: {
+      ScratchArgs = AF.add(ScratchArgs, 0, IncRef);
+      return getPersistentSummary(RetEffect::MakeAlias(0),
+                                  DoNothing, DoNothing);
+    }
+
+    case cfrelease: {
+      ScratchArgs = AF.add(ScratchArgs, 0, DecRef);
+      return getPersistentSummary(RetEffect::MakeNoRet(),
+                                  DoNothing, DoNothing);
+    }
+
+    case cfmakecollectable: {
+      ScratchArgs = AF.add(ScratchArgs, 0, MakeCollectable);
+      return getPersistentSummary(RetEffect::MakeAlias(0),DoNothing, DoNothing);
+    }
+
+    default:
+      assert (false && "Not a supported unary function.");
+      return getDefaultSummary();
+  }
+}
+
+RetainSummary* 
+RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl* FD) {
+  assert (ScratchArgs.isEmpty());
+
+  if (FD->getIdentifier() == CFDictionaryCreateII) {
+    ScratchArgs = AF.add(ScratchArgs, 1, DoNothingByRef);
+    ScratchArgs = AF.add(ScratchArgs, 2, DoNothingByRef);
+  }
+
+  return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
+}
+
+RetainSummary* 
+RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl* FD) {
+  assert (ScratchArgs.isEmpty());
+  return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
+                              DoNothing, DoNothing);
+}
+
+//===----------------------------------------------------------------------===//
+// Summary creation for Selectors.
+//===----------------------------------------------------------------------===//
+
+RetainSummary*
+RetainSummaryManager::getInitMethodSummary(QualType RetTy) {
+  assert(ScratchArgs.isEmpty());
+  // 'init' methods conceptually return a newly allocated object and claim
+  // the receiver.
+  if (cocoa::isCocoaObjectRef(RetTy) || cocoa::isCFObjectRef(RetTy))
+    return getPersistentSummary(ObjCInitRetE, DecRefMsg);
+
+  return getDefaultSummary();
+}
+
+void
+RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
+                                                   const FunctionDecl *FD) {
+  if (!FD)
+    return;
+
+  QualType RetTy = FD->getResultType();
+
+  // Determine if there is a special return effect for this method.
+  if (cocoa::isCocoaObjectRef(RetTy)) {
+    if (FD->getAttr<NSReturnsRetainedAttr>()) {
+      Summ.setRetEffect(ObjCAllocRetE);
+    }
+    else if (FD->getAttr<CFReturnsRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+    }
+    else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+    }
+    else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+    }
+  }
+  else if (RetTy->getAs<PointerType>()) {
+    if (FD->getAttr<CFReturnsRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+    }
+  }
+}
+
+void
+RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
+                                                  const ObjCMethodDecl *MD) {
+  if (!MD)
+    return;
+
+  bool isTrackedLoc = false;
+
+  // Determine if there is a special return effect for this method.
+  if (cocoa::isCocoaObjectRef(MD->getResultType())) {
+    if (MD->getAttr<NSReturnsRetainedAttr>()) {
+      Summ.setRetEffect(ObjCAllocRetE);
+      return;
+    }
+    if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
+      return;
+    }
+
+    isTrackedLoc = true;
+  }
+
+  if (!isTrackedLoc)
+    isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
+
+  if (isTrackedLoc) {
+    if (MD->getAttr<CFReturnsRetainedAttr>())
+      Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
+    else if (MD->getAttr<CFReturnsNotRetainedAttr>())
+      Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+  }
+}
+
+RetainSummary*
+RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
+                                             Selector S, QualType RetTy) {
+
+  if (MD) {
+    // Scan the method decl for 'void*' arguments.  These should be treated
+    // as 'StopTracking' because they are often used with delegates.
+    // Delegates are a frequent form of false positives with the retain
+    // count checker.
+    unsigned i = 0;
+    for (ObjCMethodDecl::param_iterator I = MD->param_begin(),
+         E = MD->param_end(); I != E; ++I, ++i)
+      if (ParmVarDecl *PD = *I) {
+        QualType Ty = Ctx.getCanonicalType(PD->getType());
+        if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy)
+          ScratchArgs = AF.add(ScratchArgs, i, StopTracking);
+      }
+  }
+
+  // Any special effect for the receiver?
+  ArgEffect ReceiverEff = DoNothing;
+
+  // If one of the arguments in the selector has the keyword 'delegate' we
+  // should stop tracking the reference count for the receiver.  This is
+  // because the reference count is quite possibly handled by a delegate
+  // method.
+  if (S.isKeywordSelector()) {
+    const std::string &str = S.getAsString();
+    assert(!str.empty());
+    if (StrInStrNoCase(str, "delegate:") != StringRef::npos)
+      ReceiverEff = StopTracking;
+  }
+
+  // Look for methods that return an owned object.
+  if (cocoa::isCocoaObjectRef(RetTy)) {
+    // EXPERIMENTAL: assume the Cocoa conventions for all objects returned
+    //  by instance methods.
+    RetEffect E = cocoa::followsFundamentalRule(S)
+                  ? ObjCAllocRetE : RetEffect::MakeNotOwned(RetEffect::ObjC);
+
+    return getPersistentSummary(E, ReceiverEff, MayEscape);
+  }
+
+  // Look for methods that return an owned core foundation object.
+  if (cocoa::isCFObjectRef(RetTy)) {
+    RetEffect E = cocoa::followsFundamentalRule(S)
+      ? RetEffect::MakeOwned(RetEffect::CF, true)
+      : RetEffect::MakeNotOwned(RetEffect::CF);
+
+    return getPersistentSummary(E, ReceiverEff, MayEscape);
+  }
+
+  if (ScratchArgs.isEmpty() && ReceiverEff == DoNothing)
+    return getDefaultSummary();
+
+  return getPersistentSummary(RetEffect::MakeNoRet(), ReceiverEff, MayEscape);
+}
+
+RetainSummary*
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+                                               const GRState *state,
+                                               const LocationContext *LC) {
+
+  // We need the type-information of the tracked receiver object
+  // Retrieve it from the state.
+  const Expr *Receiver = ME->getInstanceReceiver();
+  const ObjCInterfaceDecl* ID = 0;
+
+  // FIXME: Is this really working as expected?  There are cases where
+  //  we just use the 'ID' from the message expression.
+  SVal receiverV;
+
+  if (Receiver) {
+    receiverV = state->getSValAsScalarOrLoc(Receiver);
+
+    // FIXME: Eventually replace the use of state->get<RefBindings> with
+    // a generic API for reasoning about the Objective-C types of symbolic
+    // objects.
+    if (SymbolRef Sym = receiverV.getAsLocSymbol())
+      if (const RefVal *T = state->get<RefBindings>(Sym))
+        if (const ObjCObjectPointerType* PT =
+            T->getType()->getAs<ObjCObjectPointerType>())
+          ID = PT->getInterfaceDecl();
+
+    // FIXME: this is a hack.  This may or may not be the actual method
+    //  that is called.
+    if (!ID) {
+      if (const ObjCObjectPointerType *PT =
+          Receiver->getType()->getAs<ObjCObjectPointerType>())
+        ID = PT->getInterfaceDecl();
+    }
+  } else {
+    // FIXME: Hack for 'super'.
+    ID = ME->getReceiverInterface();
+  }
+
+  // FIXME: The receiver could be a reference to a class, meaning that
+  //  we should use the class method.
+  RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+
+  // Special-case: are we sending a mesage to "self"?
+  //  This is a hack.  When we have full-IP this should be removed.
+  if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
+    if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
+      // Get the region associated with 'self'.
+      if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
+        SVal SelfVal = state->getSVal(state->getRegion(SelfDecl, LC));
+        if (L->StripCasts() == SelfVal.getAsRegion()) {
+          // Update the summary to make the default argument effect
+          // 'StopTracking'.
+          Summ = copySummary(Summ);
+          Summ->setDefaultArgEffect(StopTracking);
+        }
+      }
+    }
+  }
+
+  return Summ ? Summ : getDefaultSummary();
+}
+
+RetainSummary*
+RetainSummaryManager::getInstanceMethodSummary(Selector S,
+                                               IdentifierInfo *ClsName,
+                                               const ObjCInterfaceDecl* ID,
+                                               const ObjCMethodDecl *MD,
+                                               QualType RetTy) {
+
+  // Look up a summary in our summary cache.
+  RetainSummary *Summ = ObjCMethodSummaries.find(ID, ClsName, S);
+
+  if (!Summ) {
+    assert(ScratchArgs.isEmpty());
+
+    // "initXXX": pass-through for receiver.
+    if (cocoa::deriveNamingConvention(S) == cocoa::InitRule)
+      Summ = getInitMethodSummary(RetTy);
+    else
+      Summ = getCommonMethodSummary(MD, S, RetTy);
+
+    // Annotations override defaults.
+    updateSummaryFromAnnotations(*Summ, MD);
+
+    // Memoize the summary.
+    ObjCMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
+  }
+
+  return Summ;
+}
+
+RetainSummary*
+RetainSummaryManager::getClassMethodSummary(Selector S, IdentifierInfo *ClsName,
+                                            const ObjCInterfaceDecl *ID,
+                                            const ObjCMethodDecl *MD,
+                                            QualType RetTy) {
+
+  assert(ClsName && "Class name must be specified.");
+  RetainSummary *Summ = ObjCClassMethodSummaries.find(ID, ClsName, S);
+
+  if (!Summ) {
+    Summ = getCommonMethodSummary(MD, S, RetTy);
+    // Annotations override defaults.
+    updateSummaryFromAnnotations(*Summ, MD);
+    // Memoize the summary.
+    ObjCClassMethodSummaries[ObjCSummaryKey(ID, ClsName, S)] = Summ;
+  }
+
+  return Summ;
+}
+
+void RetainSummaryManager::InitializeClassMethodSummaries() {
+  assert(ScratchArgs.isEmpty());
+  RetainSummary* Summ = getPersistentSummary(ObjCAllocRetE);
+
+  // Create the [NSAssertionHandler currentHander] summary.
+  addClassMethSummary("NSAssertionHandler", "currentHandler",
+                getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::ObjC)));
+
+  // Create the [NSAutoreleasePool addObject:] summary.
+  ScratchArgs = AF.add(ScratchArgs, 0, Autorelease);
+  addClassMethSummary("NSAutoreleasePool", "addObject",
+                      getPersistentSummary(RetEffect::MakeNoRet(),
+                                           DoNothing, Autorelease));
+
+  // Create the summaries for [NSObject performSelector...].  We treat
+  // these as 'stop tracking' for the arguments because they are often
+  // used for delegates that can release the object.  When we have better
+  // inter-procedural analysis we can potentially do something better.  This
+  // workaround is to remove false positives.
+  Summ = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, StopTracking);
+  IdentifierInfo *NSObjectII = &Ctx.Idents.get("NSObject");
+  addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
+                    "afterDelay", NULL);
+  addClsMethSummary(NSObjectII, Summ, "performSelector", "withObject",
+                    "afterDelay", "inModes", NULL);
+  addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread",
+                    "withObject", "waitUntilDone", NULL);
+  addClsMethSummary(NSObjectII, Summ, "performSelectorOnMainThread",
+                    "withObject", "waitUntilDone", "modes", NULL);
+  addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread",
+                    "withObject", "waitUntilDone", NULL);
+  addClsMethSummary(NSObjectII, Summ, "performSelector", "onThread",
+                    "withObject", "waitUntilDone", "modes", NULL);
+  addClsMethSummary(NSObjectII, Summ, "performSelectorInBackground",
+                    "withObject", NULL);
+}
+
+void RetainSummaryManager::InitializeMethodSummaries() {
+
+  assert (ScratchArgs.isEmpty());
+
+  // Create the "init" selector.  It just acts as a pass-through for the
+  // receiver.
+  RetainSummary *InitSumm = getPersistentSummary(ObjCInitRetE, DecRefMsg);
+  addNSObjectMethSummary(GetNullarySelector("init", Ctx), InitSumm);
+
+  // awakeAfterUsingCoder: behaves basically like an 'init' method.  It
+  // claims the receiver and returns a retained object.
+  addNSObjectMethSummary(GetUnarySelector("awakeAfterUsingCoder", Ctx),
+                         InitSumm);
+
+  // The next methods are allocators.
+  RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE);
+  RetainSummary *CFAllocSumm =
+    getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
+
+  // Create the "retain" selector.
+  RetEffect E = RetEffect::MakeReceiverAlias();
+  RetainSummary *Summ = getPersistentSummary(E, IncRefMsg);
+  addNSObjectMethSummary(GetNullarySelector("retain", Ctx), Summ);
+
+  // Create the "release" selector.
+  Summ = getPersistentSummary(E, DecRefMsg);
+  addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
+
+  // Create the "drain" selector.
+  Summ = getPersistentSummary(E, isGCEnabled() ? DoNothing : DecRef);
+  addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);
+
+  // Create the -dealloc summary.
+  Summ = getPersistentSummary(RetEffect::MakeNoRet(), Dealloc);
+  addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
+
+  // Create the "autorelease" selector.
+  Summ = getPersistentSummary(E, Autorelease);
+  addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
+
+  // Specially handle NSAutoreleasePool.
+  addInstMethSummary("NSAutoreleasePool", "init",
+                     getPersistentSummary(RetEffect::MakeReceiverAlias(),
+                                          NewAutoreleasePool));
+
+  // For NSWindow, allocated objects are (initially) self-owned.
+  // FIXME: For now we opt for false negatives with NSWindow, as these objects
+  //  self-own themselves.  However, they only do this once they are displayed.
+  //  Thus, we need to track an NSWindow's display status.
+  //  This is tracked in <rdar://problem/6062711>.
+  //  See also http://llvm.org/bugs/show_bug.cgi?id=3714.
+  RetainSummary *NoTrackYet = getPersistentSummary(RetEffect::MakeNoRet(),
+                                                   StopTracking,
+                                                   StopTracking);
+
+  addClassMethSummary("NSWindow", "alloc", NoTrackYet);
+
+#if 0
+  addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect",
+                     "styleMask", "backing", "defer", NULL);
+
+  addInstMethSummary("NSWindow", NoTrackYet, "initWithContentRect",
+                     "styleMask", "backing", "defer", "screen", NULL);
+#endif
+
+  // For NSPanel (which subclasses NSWindow), allocated objects are not
+  //  self-owned.
+  // FIXME: For now we don't track NSPanels. object for the same reason
+  //   as for NSWindow objects.
+  addClassMethSummary("NSPanel", "alloc", NoTrackYet);
+
+#if 0
+  addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect",
+                     "styleMask", "backing", "defer", NULL);
+
+  addInstMethSummary("NSPanel", NoTrackYet, "initWithContentRect",
+                     "styleMask", "backing", "defer", "screen", NULL);
+#endif
+
+  // Don't track allocated autorelease pools yet, as it is okay to prematurely
+  // exit a method.
+  addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
+
+  // Create NSAssertionHandler summaries.
+  addPanicSummary("NSAssertionHandler", "handleFailureInFunction", "file",
+                  "lineNumber", "description", NULL);
+
+  addPanicSummary("NSAssertionHandler", "handleFailureInMethod", "object",
+                  "file", "lineNumber", "description", NULL);
+
+  // Create summaries QCRenderer/QCView -createSnapShotImageOfType:
+  addInstMethSummary("QCRenderer", AllocSumm,
+                     "createSnapshotImageOfType", NULL);
+  addInstMethSummary("QCView", AllocSumm,
+                     "createSnapshotImageOfType", NULL);
+
+  // Create summaries for CIContext, 'createCGImage' and
+  // 'createCGLayerWithSize'.  These objects are CF objects, and are not
+  // automatically garbage collected.
+  addInstMethSummary("CIContext", CFAllocSumm,
+                     "createCGImage", "fromRect", NULL);
+  addInstMethSummary("CIContext", CFAllocSumm,
+                     "createCGImage", "fromRect", "format", "colorSpace", NULL);
+  addInstMethSummary("CIContext", CFAllocSumm, "createCGLayerWithSize",
+           "info", NULL);
+}
+
+//===----------------------------------------------------------------------===//
+// AutoreleaseBindings - State used to track objects in autorelease pools.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, unsigned> ARCounts;
+typedef llvm::ImmutableMap<SymbolRef, ARCounts> ARPoolContents;
+typedef llvm::ImmutableList<SymbolRef> ARStack;
+
+static int AutoRCIndex = 0;
+static int AutoRBIndex = 0;
+
+namespace { class AutoreleasePoolContents {}; }
+namespace { class AutoreleaseStack {}; }
+
+namespace clang {
+namespace ento {
+template<> struct GRStateTrait<AutoreleaseStack>
+  : public GRStatePartialTrait<ARStack> {
+  static inline void* GDMIndex() { return &AutoRBIndex; }
+};
+
+template<> struct GRStateTrait<AutoreleasePoolContents>
+  : public GRStatePartialTrait<ARPoolContents> {
+  static inline void* GDMIndex() { return &AutoRCIndex; }
+};
+} // end GR namespace
+} // end clang namespace
+
+static SymbolRef GetCurrentAutoreleasePool(const GRState* state) {
+  ARStack stack = state->get<AutoreleaseStack>();
+  return stack.isEmpty() ? SymbolRef() : stack.getHead();
+}
+
+static const GRState * SendAutorelease(const GRState *state,
+                                       ARCounts::Factory &F, SymbolRef sym) {
+
+  SymbolRef pool = GetCurrentAutoreleasePool(state);
+  const ARCounts *cnts = state->get<AutoreleasePoolContents>(pool);
+  ARCounts newCnts(0);
+
+  if (cnts) {
+    const unsigned *cnt = (*cnts).lookup(sym);
+    newCnts = F.add(*cnts, sym, cnt ? *cnt  + 1 : 1);
+  }
+  else
+    newCnts = F.add(F.getEmptyMap(), sym, 1);
+
+  return state->set<AutoreleasePoolContents>(pool, newCnts);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class CFRefCount : public TransferFuncs {
+public:
+  class BindingsPrinter : public GRState::Printer {
+  public:
+    virtual void Print(llvm::raw_ostream& Out, const GRState* state,
+                       const char* nl, const char* sep);
+  };
+
+private:
+  typedef llvm::DenseMap<const ExplodedNode*, const RetainSummary*>
+    SummaryLogTy;
+
+  RetainSummaryManager Summaries;
+  SummaryLogTy SummaryLog;
+  const LangOptions&   LOpts;
+  ARCounts::Factory    ARCountFactory;
+
+  BugType *useAfterRelease, *releaseNotOwned;
+  BugType *deallocGC, *deallocNotOwned;
+  BugType *leakWithinFunction, *leakAtReturn;
+  BugType *overAutorelease;
+  BugType *returnNotOwnedForOwned;
+  BugReporter *BR;
+
+  const GRState * Update(const GRState * state, SymbolRef sym, RefVal V, ArgEffect E,
+                    RefVal::Kind& hasErr);
+
+  void ProcessNonLeakError(ExplodedNodeSet& Dst,
+                           StmtNodeBuilder& Builder,
+                           const Expr* NodeExpr, SourceRange ErrorRange,
+                           ExplodedNode* Pred,
+                           const GRState* St,
+                           RefVal::Kind hasErr, SymbolRef Sym);
+
+  const GRState * HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
+                               llvm::SmallVectorImpl<SymbolRef> &Leaked);
+
+  ExplodedNode* ProcessLeaks(const GRState * state,
+                                      llvm::SmallVectorImpl<SymbolRef> &Leaked,
+                                      GenericNodeBuilder &Builder,
+                                      ExprEngine &Eng,
+                                      ExplodedNode *Pred = 0);
+
+public:
+  CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
+    : Summaries(Ctx, gcenabled),
+      LOpts(lopts), useAfterRelease(0), releaseNotOwned(0),
+      deallocGC(0), deallocNotOwned(0),
+      leakWithinFunction(0), leakAtReturn(0), overAutorelease(0),
+      returnNotOwnedForOwned(0), BR(0) {}
+
+  virtual ~CFRefCount() {}
+
+  void RegisterChecks(ExprEngine &Eng);
+
+  virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {
+    Printers.push_back(new BindingsPrinter());
+  }
+
+  bool isGCEnabled() const { return Summaries.isGCEnabled(); }
+  const LangOptions& getLangOptions() const { return LOpts; }
+
+  const RetainSummary *getSummaryOfNode(const ExplodedNode *N) const {
+    SummaryLogTy::const_iterator I = SummaryLog.find(N);
+    return I == SummaryLog.end() ? 0 : I->second;
+  }
+
+  // Calls.
+
+  void evalSummary(ExplodedNodeSet& Dst,
+                   ExprEngine& Eng,
+                   StmtNodeBuilder& Builder,
+                   const Expr* Ex,
+                   InstanceReceiver Receiver,
+                   const RetainSummary& Summ,
+                   const MemRegion *Callee,
+                   ConstExprIterator arg_beg, ConstExprIterator arg_end,
+                   ExplodedNode* Pred, const GRState *state);
+
+  virtual void evalCall(ExplodedNodeSet& Dst,
+                        ExprEngine& Eng,
+                        StmtNodeBuilder& Builder,
+                        const CallExpr* CE, SVal L,
+                        ExplodedNode* Pred);
+
+
+  virtual void evalObjCMessageExpr(ExplodedNodeSet& Dst,
+                                   ExprEngine& Engine,
+                                   StmtNodeBuilder& Builder,
+                                   const ObjCMessageExpr* ME,
+                                   ExplodedNode* Pred,
+                                   const GRState *state);
+  // Stores.
+  virtual void evalBind(StmtNodeBuilderRef& B, SVal location, SVal val);
+
+  // End-of-path.
+
+  virtual void evalEndPath(ExprEngine& Engine,
+                           EndPathNodeBuilder& Builder);
+
+  virtual void evalDeadSymbols(ExplodedNodeSet& Dst,
+                               ExprEngine& Engine,
+                               StmtNodeBuilder& Builder,
+                               ExplodedNode* Pred,
+                               const GRState* state,
+                               SymbolReaper& SymReaper);
+
+  std::pair<ExplodedNode*, const GRState *>
+  HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd,
+                          ExplodedNode* Pred, ExprEngine &Eng,
+                          SymbolRef Sym, RefVal V, bool &stop);
+  // Return statements.
+
+  virtual void evalReturn(ExplodedNodeSet& Dst,
+                          ExprEngine& Engine,
+                          StmtNodeBuilder& Builder,
+                          const ReturnStmt* S,
+                          ExplodedNode* Pred);
+
+  // Assumptions.
+
+  virtual const GRState *evalAssume(const GRState* state, SVal condition,
+                                    bool assumption);
+};
+
+} // end anonymous namespace
+
+static void PrintPool(llvm::raw_ostream &Out, SymbolRef Sym,
+                      const GRState *state) {
+  Out << ' ';
+  if (Sym)
+    Out << Sym->getSymbolID();
+  else
+    Out << "<pool>";
+  Out << ":{";
+
+  // Get the contents of the pool.
+  if (const ARCounts *cnts = state->get<AutoreleasePoolContents>(Sym))
+    for (ARCounts::iterator J=cnts->begin(), EJ=cnts->end(); J != EJ; ++J)
+      Out << '(' << J.getKey() << ',' << J.getData() << ')';
+
+  Out << '}';
+}
+
+void CFRefCount::BindingsPrinter::Print(llvm::raw_ostream& Out,
+                                        const GRState* state,
+                                        const char* nl, const char* sep) {
+
+  RefBindings B = state->get<RefBindings>();
+
+  if (!B.isEmpty())
+    Out << sep << nl;
+
+  for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+    Out << (*I).first << " : ";
+    (*I).second.print(Out);
+    Out << nl;
+  }
+
+  // Print the autorelease stack.
+  Out << sep << nl << "AR pool stack:";
+  ARStack stack = state->get<AutoreleaseStack>();
+
+  PrintPool(Out, SymbolRef(), state);  // Print the caller's pool.
+  for (ARStack::iterator I=stack.begin(), E=stack.end(); I!=E; ++I)
+    PrintPool(Out, *I, state);
+
+  Out << nl;
+}
+
+//===----------------------------------------------------------------------===//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+  //===-------------===//
+  // Bug Descriptions. //
+  //===-------------===//
+
+  class CFRefBug : public BugType {
+  protected:
+    CFRefCount& TF;
+
+    CFRefBug(CFRefCount* tf, llvm::StringRef name)
+    : BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
+  public:
+
+    CFRefCount& getTF() { return TF; }
+
+    // FIXME: Eventually remove.
+    virtual const char* getDescription() const = 0;
+
+    virtual bool isLeak() const { return false; }
+  };
+
+  class UseAfterRelease : public CFRefBug {
+  public:
+    UseAfterRelease(CFRefCount* tf)
+    : CFRefBug(tf, "Use-after-release") {}
+
+    const char* getDescription() const {
+      return "Reference-counted object is used after it is released";
+    }
+  };
+
+  class BadRelease : public CFRefBug {
+  public:
+    BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {}
+
+    const char* getDescription() const {
+      return "Incorrect decrement of the reference count of an object that is "
+             "not owned at this point by the caller";
+    }
+  };
+
+  class DeallocGC : public CFRefBug {
+  public:
+    DeallocGC(CFRefCount *tf)
+      : CFRefBug(tf, "-dealloc called while using garbage collection") {}
+
+    const char *getDescription() const {
+      return "-dealloc called while using garbage collection";
+    }
+  };
+
+  class DeallocNotOwned : public CFRefBug {
+  public:
+    DeallocNotOwned(CFRefCount *tf)
+      : CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {}
+
+    const char *getDescription() const {
+      return "-dealloc sent to object that may be referenced elsewhere";
+    }
+  };
+
+  class OverAutorelease : public CFRefBug {
+  public:
+    OverAutorelease(CFRefCount *tf) :
+      CFRefBug(tf, "Object sent -autorelease too many times") {}
+
+    const char *getDescription() const {
+      return "Object sent -autorelease too many times";
+    }
+  };
+
+  class ReturnedNotOwnedForOwned : public CFRefBug {
+  public:
+    ReturnedNotOwnedForOwned(CFRefCount *tf) :
+      CFRefBug(tf, "Method should return an owned object") {}
+
+    const char *getDescription() const {
+      return "Object with +0 retain counts returned to caller where a +1 "
+             "(owning) retain count is expected";
+    }
+  };
+
+  class Leak : public CFRefBug {
+    const bool isReturn;
+  protected:
+    Leak(CFRefCount* tf, llvm::StringRef name, bool isRet)
+    : CFRefBug(tf, name), isReturn(isRet) {}
+  public:
+
+    const char* getDescription() const { return ""; }
+
+    bool isLeak() const { return true; }
+  };
+
+  class LeakAtReturn : public Leak {
+  public:
+    LeakAtReturn(CFRefCount* tf, llvm::StringRef name)
+    : Leak(tf, name, true) {}
+  };
+
+  class LeakWithinFunction : public Leak {
+  public:
+    LeakWithinFunction(CFRefCount* tf, llvm::StringRef name)
+    : Leak(tf, name, false) {}
+  };
+
+  //===---------===//
+  // Bug Reports.  //
+  //===---------===//
+
+  class CFRefReport : public RangedBugReport {
+  protected:
+    SymbolRef Sym;
+    const CFRefCount &TF;
+  public:
+    CFRefReport(CFRefBug& D, const CFRefCount &tf,
+                ExplodedNode *n, SymbolRef sym)
+      : RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {}
+
+    CFRefReport(CFRefBug& D, const CFRefCount &tf,
+                ExplodedNode *n, SymbolRef sym, llvm::StringRef endText)
+      : RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {}
+
+    virtual ~CFRefReport() {}
+
+    CFRefBug& getBugType() const {
+      return (CFRefBug&) RangedBugReport::getBugType();
+    }
+
+    virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
+      if (!getBugType().isLeak())
+        return RangedBugReport::getRanges();
+      else
+        return std::make_pair(ranges_iterator(), ranges_iterator());
+    }
+
+    SymbolRef getSymbol() const { return Sym; }
+
+    PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
+                                    const ExplodedNode* N);
+
+    std::pair<const char**,const char**> getExtraDescriptiveText();
+
+    PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
+                                   const ExplodedNode* PrevN,
+                                   BugReporterContext& BRC);
+  };
+
+  class CFRefLeakReport : public CFRefReport {
+    SourceLocation AllocSite;
+    const MemRegion* AllocBinding;
+  public:
+    CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
+                    ExplodedNode *n, SymbolRef sym,
+                    ExprEngine& Eng);
+
+    PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
+                                    const ExplodedNode* N);
+
+    SourceLocation getLocation() const { return AllocSite; }
+  };
+} // end anonymous namespace
+
+
+
+static const char* Msgs[] = {
+  // GC only
+  "Code is compiled to only use garbage collection",
+  // No GC.
+  "Code is compiled to use reference counts",
+  // Hybrid, with GC.
+  "Code is compiled to use either garbage collection (GC) or reference counts"
+  " (non-GC).  The bug occurs with GC enabled",
+  // Hybrid, without GC
+  "Code is compiled to use either garbage collection (GC) or reference counts"
+  " (non-GC).  The bug occurs in non-GC mode"
+};
+
+std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() {
+  CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF();
+
+  switch (TF.getLangOptions().getGCMode()) {
+    default:
+      assert(false);
+
+    case LangOptions::GCOnly:
+      assert (TF.isGCEnabled());
+      return std::make_pair(&Msgs[0], &Msgs[0]+1);
+
+    case LangOptions::NonGC:
+      assert (!TF.isGCEnabled());
+      return std::make_pair(&Msgs[1], &Msgs[1]+1);
+
+    case LangOptions::HybridGC:
+      if (TF.isGCEnabled())
+        return std::make_pair(&Msgs[2], &Msgs[2]+1);
+      else
+        return std::make_pair(&Msgs[3], &Msgs[3]+1);
+  }
+}
+
+static inline bool contains(const llvm::SmallVectorImpl<ArgEffect>& V,
+                            ArgEffect X) {
+  for (llvm::SmallVectorImpl<ArgEffect>::const_iterator I=V.begin(), E=V.end();
+       I!=E; ++I)
+    if (*I == X) return true;
+
+  return false;
+}
+
+PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
+                                            const ExplodedNode* PrevN,
+                                            BugReporterContext& BRC) {
+
+  if (!isa<PostStmt>(N->getLocation()))
+    return NULL;
+
+  // Check if the type state has changed.
+  const GRState *PrevSt = PrevN->getState();
+  const GRState *CurrSt = N->getState();
+
+  const RefVal* CurrT = CurrSt->get<RefBindings>(Sym);
+  if (!CurrT) return NULL;
+
+  const RefVal &CurrV = *CurrT;
+  const RefVal *PrevT = PrevSt->get<RefBindings>(Sym);
+
+  // Create a string buffer to constain all the useful things we want
+  // to tell the user.
+  std::string sbuf;
+  llvm::raw_string_ostream os(sbuf);
+
+  // This is the allocation site since the previous node had no bindings
+  // for this symbol.
+  if (!PrevT) {
+    const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+    if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
+      // Get the name of the callee (if it is available).
+      SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
+      if (const FunctionDecl* FD = X.getAsFunctionDecl())
+        os << "Call to function '" << FD << '\'';
+      else
+        os << "function call";
+    }
+    else {
+      assert (isa<ObjCMessageExpr>(S));
+      os << "Method";
+    }
+
+    if (CurrV.getObjKind() == RetEffect::CF) {
+      os << " returns a Core Foundation object with a ";
+    }
+    else {
+      assert (CurrV.getObjKind() == RetEffect::ObjC);
+      os << " returns an Objective-C object with a ";
+    }
+
+    if (CurrV.isOwned()) {
+      os << "+1 retain count (owning reference).";
+
+      if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) {
+        assert(CurrV.getObjKind() == RetEffect::CF);
+        os << "  "
+        "Core Foundation objects are not automatically garbage collected.";
+      }
+    }
+    else {
+      assert (CurrV.isNotOwned());
+      os << "+0 retain count (non-owning reference).";
+    }
+
+    PathDiagnosticLocation Pos(S, BRC.getSourceManager());
+    return new PathDiagnosticEventPiece(Pos, os.str());
+  }
+
+  // Gather up the effects that were performed on the object at this
+  // program point
+  llvm::SmallVector<ArgEffect, 2> AEffects;
+
+  if (const RetainSummary *Summ =
+        TF.getSummaryOfNode(BRC.getNodeResolver().getOriginalNode(N))) {
+    // We only have summaries attached to nodes after evaluating CallExpr and
+    // ObjCMessageExprs.
+    const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+    if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
+      // Iterate through the parameter expressions and see if the symbol
+      // was ever passed as an argument.
+      unsigned i = 0;
+
+      for (CallExpr::const_arg_iterator AI=CE->arg_begin(), AE=CE->arg_end();
+           AI!=AE; ++AI, ++i) {
+
+        // Retrieve the value of the argument.  Is it the symbol
+        // we are interested in?
+        if (CurrSt->getSValAsScalarOrLoc(*AI).getAsLocSymbol() != Sym)
+          continue;
+
+        // We have an argument.  Get the effect!
+        AEffects.push_back(Summ->getArg(i));
+      }
+    }
+    else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
+      if (const Expr *receiver = ME->getInstanceReceiver())
+        if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
+          // The symbol we are tracking is the receiver.
+          AEffects.push_back(Summ->getReceiverEffect());
+        }
+    }
+  }
+
+  do {
+    // Get the previous type state.
+    RefVal PrevV = *PrevT;
+
+    // Specially handle -dealloc.
+    if (!TF.isGCEnabled() && contains(AEffects, Dealloc)) {
+      // Determine if the object's reference count was pushed to zero.
+      assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
+      // We may not have transitioned to 'release' if we hit an error.
+      // This case is handled elsewhere.
+      if (CurrV.getKind() == RefVal::Released) {
+        assert(CurrV.getCombinedCounts() == 0);
+        os << "Object released by directly sending the '-dealloc' message";
+        break;
+      }
+    }
+
+    // Specially handle CFMakeCollectable and friends.
+    if (contains(AEffects, MakeCollectable)) {
+      // Get the name of the function.
+      const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+      SVal X = CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee());
+      const FunctionDecl* FD = X.getAsFunctionDecl();
+      const std::string& FName = FD->getNameAsString();
+
+      if (TF.isGCEnabled()) {
+        // Determine if the object's reference count was pushed to zero.
+        assert(!(PrevV == CurrV) && "The typestate *must* have changed.");
+
+        os << "In GC mode a call to '" << FName
+        <<  "' decrements an object's retain count and registers the "
+        "object with the garbage collector. ";
+
+        if (CurrV.getKind() == RefVal::Released) {
+          assert(CurrV.getCount() == 0);
+          os << "Since it now has a 0 retain count the object can be "
+          "automatically collected by the garbage collector.";
+        }
+        else
+          os << "An object must have a 0 retain count to be garbage collected. "
+          "After this call its retain count is +" << CurrV.getCount()
+          << '.';
+      }
+      else
+        os << "When GC is not enabled a call to '" << FName
+        << "' has no effect on its argument.";
+
+      // Nothing more to say.
+      break;
+    }
+
+    // Determine if the typestate has changed.
+    if (!(PrevV == CurrV))
+      switch (CurrV.getKind()) {
+        case RefVal::Owned:
+        case RefVal::NotOwned:
+
+          if (PrevV.getCount() == CurrV.getCount()) {
+            // Did an autorelease message get sent?
+            if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
+              return 0;
+
+            assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
+            os << "Object sent -autorelease message";
+            break;
+          }
+
+          if (PrevV.getCount() > CurrV.getCount())
+            os << "Reference count decremented.";
+          else
+            os << "Reference count incremented.";
+
+          if (unsigned Count = CurrV.getCount())
+            os << " The object now has a +" << Count << " retain count.";
+
+          if (PrevV.getKind() == RefVal::Released) {
+            assert(TF.isGCEnabled() && CurrV.getCount() > 0);
+            os << " The object is not eligible for garbage collection until the "
+            "retain count reaches 0 again.";
+          }
+
+          break;
+
+        case RefVal::Released:
+          os << "Object released.";
+          break;
+
+        case RefVal::ReturnedOwned:
+          os << "Object returned to caller as an owning reference (single retain "
+          "count transferred to caller).";
+          break;
+
+        case RefVal::ReturnedNotOwned:
+          os << "Object returned to caller with a +0 (non-owning) retain count.";
+          break;
+
+        default:
+          return NULL;
+      }
+
+    // Emit any remaining diagnostics for the argument effects (if any).
+    for (llvm::SmallVectorImpl<ArgEffect>::iterator I=AEffects.begin(),
+         E=AEffects.end(); I != E; ++I) {
+
+      // A bunch of things have alternate behavior under GC.
+      if (TF.isGCEnabled())
+        switch (*I) {
+          default: break;
+          case Autorelease:
+            os << "In GC mode an 'autorelease' has no effect.";
+            continue;
+          case IncRefMsg:
+            os << "In GC mode the 'retain' message has no effect.";
+            continue;
+          case DecRefMsg:
+            os << "In GC mode the 'release' message has no effect.";
+            continue;
+        }
+    }
+  } while (0);
+
+  if (os.str().empty())
+    return 0; // We have nothing to say!
+
+  const Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+  PathDiagnosticLocation Pos(S, BRC.getSourceManager());
+  PathDiagnosticPiece* P = new PathDiagnosticEventPiece(Pos, os.str());
+
+  // Add the range by scanning the children of the statement for any bindings
+  // to Sym.
+  for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+       I!=E; ++I)
+    if (const Expr* Exp = dyn_cast_or_null<Expr>(*I))
+      if (CurrSt->getSValAsScalarOrLoc(Exp).getAsLocSymbol() == Sym) {
+        P->addRange(Exp->getSourceRange());
+        break;
+      }
+
+  return P;
+}
+
+namespace {
+  class FindUniqueBinding :
+  public StoreManager::BindingsHandler {
+    SymbolRef Sym;
+    const MemRegion* Binding;
+    bool First;
+
+  public:
+    FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {}
+
+    bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
+                       SVal val) {
+
+      SymbolRef SymV = val.getAsSymbol();
+      if (!SymV || SymV != Sym)
+        return true;
+
+      if (Binding) {
+        First = false;
+        return false;
+      }
+      else
+        Binding = R;
+
+      return true;
+    }
+
+    operator bool() { return First && Binding; }
+    const MemRegion* getRegion() { return Binding; }
+  };
+}
+
+static std::pair<const ExplodedNode*,const MemRegion*>
+GetAllocationSite(GRStateManager& StateMgr, const ExplodedNode* N,
+                  SymbolRef Sym) {
+
+  // Find both first node that referred to the tracked symbol and the
+  // memory location that value was store to.
+  const ExplodedNode* Last = N;
+  const MemRegion* FirstBinding = 0;
+
+  while (N) {
+    const GRState* St = N->getState();
+    RefBindings B = St->get<RefBindings>();
+
+    if (!B.lookup(Sym))
+      break;
+
+    FindUniqueBinding FB(Sym);
+    StateMgr.iterBindings(St, FB);
+    if (FB) FirstBinding = FB.getRegion();
+
+    Last = N;
+    N = N->pred_empty() ? NULL : *(N->pred_begin());
+  }
+
+  return std::make_pair(Last, FirstBinding);
+}
+
+PathDiagnosticPiece*
+CFRefReport::getEndPath(BugReporterContext& BRC,
+                        const ExplodedNode* EndN) {
+  // Tell the BugReporterContext to report cases when the tracked symbol is
+  // assigned to different variables, etc.
+  BRC.addNotableSymbol(Sym);
+  return RangedBugReport::getEndPath(BRC, EndN);
+}
+
+PathDiagnosticPiece*
+CFRefLeakReport::getEndPath(BugReporterContext& BRC,
+                            const ExplodedNode* EndN){
+
+  // Tell the BugReporterContext to report cases when the tracked symbol is
+  // assigned to different variables, etc.
+  BRC.addNotableSymbol(Sym);
+
+  // We are reporting a leak.  Walk up the graph to get to the first node where
+  // the symbol appeared, and also get the first VarDecl that tracked object
+  // is stored to.
+  const ExplodedNode* AllocNode = 0;
+  const MemRegion* FirstBinding = 0;
+
+  llvm::tie(AllocNode, FirstBinding) =
+    GetAllocationSite(BRC.getStateManager(), EndN, Sym);
+
+  // Get the allocate site.
+  assert(AllocNode);
+  const Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
+
+  SourceManager& SMgr = BRC.getSourceManager();
+  unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart());
+
+  // Compute an actual location for the leak.  Sometimes a leak doesn't
+  // occur at an actual statement (e.g., transition between blocks; end
+  // of function) so we need to walk the graph and compute a real location.
+  const ExplodedNode* LeakN = EndN;
+  PathDiagnosticLocation L;
+
+  while (LeakN) {
+    ProgramPoint P = LeakN->getLocation();
+
+    if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+      L = PathDiagnosticLocation(PS->getStmt()->getLocStart(), SMgr);
+      break;
+    }
+    else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+      if (const Stmt* Term = BE->getSrc()->getTerminator()) {
+        L = PathDiagnosticLocation(Term->getLocStart(), SMgr);
+        break;
+      }
+    }
+
+    LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin());
+  }
+
+  if (!L.isValid()) {
+    const Decl &D = EndN->getCodeDecl();
+    L = PathDiagnosticLocation(D.getBodyRBrace(), SMgr);
+  }
+
+  std::string sbuf;
+  llvm::raw_string_ostream os(sbuf);
+
+  os << "Object allocated on line " << AllocLine;
+
+  if (FirstBinding)
+    os << " and stored into '" << FirstBinding->getString() << '\'';
+
+  // Get the retain count.
+  const RefVal* RV = EndN->getState()->get<RefBindings>(Sym);
+
+  if (RV->getKind() == RefVal::ErrorLeakReturned) {
+    // FIXME: Per comments in rdar://6320065, "create" only applies to CF
+    // ojbects.  Only "copy", "alloc", "retain" and "new" transfer ownership
+    // to the caller for NS objects.
+    ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
+    os << " is returned from a method whose name ('"
+       << MD.getSelector().getAsString()
+    << "') does not contain 'copy' or otherwise starts with"
+    " 'new' or 'alloc'.  This violates the naming convention rules given"
+    " in the Memory Management Guide for Cocoa (object leaked)";
+  }
+  else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
+    ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
+    os << " and returned from method '" << MD.getSelector().getAsString()
+       << "' is potentially leaked when using garbage collection.  Callers "
+          "of this method do not expect a returned object with a +1 retain "
+          "count since they expect the object to be managed by the garbage "
+          "collector";
+  }
+  else
+    os << " is not referenced later in this execution path and has a retain "
+          "count of +" << RV->getCount() << " (object leaked)";
+
+  return new PathDiagnosticEventPiece(L, os.str());
+}
+
+CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf,
+                                 ExplodedNode *n,
+                                 SymbolRef sym, ExprEngine& Eng)
+: CFRefReport(D, tf, n, sym) {
+
+  // Most bug reports are cached at the location where they occured.
+  // With leaks, we want to unique them by the location where they were
+  // allocated, and only report a single path.  To do this, we need to find
+  // the allocation site of a piece of tracked memory, which we do via a
+  // call to GetAllocationSite.  This will walk the ExplodedGraph backwards.
+  // Note that this is *not* the trimmed graph; we are guaranteed, however,
+  // that all ancestor nodes that represent the allocation site have the
+  // same SourceLocation.
+  const ExplodedNode* AllocNode = 0;
+
+  llvm::tie(AllocNode, AllocBinding) =  // Set AllocBinding.
+    GetAllocationSite(Eng.getStateManager(), getErrorNode(), getSymbol());
+
+  // Get the SourceLocation for the allocation site.
+  ProgramPoint P = AllocNode->getLocation();
+  AllocSite = cast<PostStmt>(P).getStmt()->getLocStart();
+
+  // Fill in the description of the bug.
+  Description.clear();
+  llvm::raw_string_ostream os(Description);
+  SourceManager& SMgr = Eng.getContext().getSourceManager();
+  unsigned AllocLine = SMgr.getInstantiationLineNumber(AllocSite);
+  os << "Potential leak ";
+  if (tf.isGCEnabled()) {
+    os << "(when using garbage collection) ";
+  }
+  os << "of an object allocated on line " << AllocLine;
+
+  // FIXME: AllocBinding doesn't get populated for RegionStore yet.
+  if (AllocBinding)
+    os << " and stored into '" << AllocBinding->getString() << '\'';
+}
+
+//===----------------------------------------------------------------------===//
+// Main checker logic.
+//===----------------------------------------------------------------------===//
+
+/// GetReturnType - Used to get the return type of a message expression or
+///  function call with the intention of affixing that type to a tracked symbol.
+///  While the the return type can be queried directly from RetEx, when
+///  invoking class methods we augment to the return type to be that of
+///  a pointer to the class (as opposed it just being id).
+static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
+  QualType RetTy = RetE->getType();
+  // If RetE is not a message expression just return its type.
+  // If RetE is a message expression, return its types if it is something
+  /// more specific than id.
+  if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
+    if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
+      if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
+          PT->isObjCClassType()) {
+        // At this point we know the return type of the message expression is
+        // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
+        // is a call to a class method whose type we can resolve.  In such
+        // cases, promote the return type to XXX* (where XXX is the class).
+        const ObjCInterfaceDecl *D = ME->getReceiverInterface();
+        return !D ? RetTy :
+                    Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D));
+      }
+
+  return RetTy;
+}
+
+void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
+                             ExprEngine& Eng,
+                             StmtNodeBuilder& Builder,
+                             const Expr* Ex,
+                             InstanceReceiver Receiver,
+                             const RetainSummary& Summ,
+                             const MemRegion *Callee,
+                             ConstExprIterator arg_beg, 
+                             ConstExprIterator arg_end,
+                             ExplodedNode* Pred, const GRState *state) {
+
+  // Evaluate the effect of the arguments.
+  RefVal::Kind hasErr = (RefVal::Kind) 0;
+  unsigned idx = 0;
+  SourceRange ErrorRange;
+  SymbolRef ErrorSym = 0;
+
+  llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
+
+  // HACK: Symbols that have ref-count state that are referenced directly
+  //  (not as structure or array elements, or via bindings) by an argument
+  //  should not have their ref-count state stripped after we have
+  //  done an invalidation pass.
+  llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+
+  for (ConstExprIterator I = arg_beg; I != arg_end; ++I, ++idx) {
+    SVal V = state->getSValAsScalarOrLoc(*I);
+    SymbolRef Sym = V.getAsLocSymbol();
+
+    if (Sym)
+      if (RefBindings::data_type* T = state->get<RefBindings>(Sym)) {
+        WhitelistedSymbols.insert(Sym);
+        state = Update(state, Sym, *T, Summ.getArg(idx), hasErr);
+        if (hasErr) {
+          ErrorRange = (*I)->getSourceRange();
+          ErrorSym = Sym;
+          break;
+        }
+      }
+
+  tryAgain:
+    if (isa<Loc>(V)) {
+      if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(&V)) {
+        if (Summ.getArg(idx) == DoNothingByRef)
+          continue;
+
+        // Invalidate the value of the variable passed by reference.
+        const MemRegion *R = MR->getRegion();
+
+        // Are we dealing with an ElementRegion?  If the element type is
+        // a basic integer type (e.g., char, int) and the underying region
+        // is a variable region then strip off the ElementRegion.
+        // FIXME: We really need to think about this for the general case
+        //   as sometimes we are reasoning about arrays and other times
+        //   about (char*), etc., is just a form of passing raw bytes.
+        //   e.g., void *p = alloca(); foo((char*)p);
+        if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+          // Checking for 'integral type' is probably too promiscuous, but
+          // we'll leave it in for now until we have a systematic way of
+          // handling all of these cases.  Eventually we need to come up
+          // with an interface to StoreManager so that this logic can be
+          // approriately delegated to the respective StoreManagers while
+          // still allowing us to do checker-specific logic (e.g.,
+          // invalidating reference counts), probably via callbacks.
+          if (ER->getElementType()->isIntegralOrEnumerationType()) {
+            const MemRegion *superReg = ER->getSuperRegion();
+            if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+                isa<ObjCIvarRegion>(superReg))
+              R = cast<TypedRegion>(superReg);
+          }
+          // FIXME: What about layers of ElementRegions?
+        }
+
+        // Mark this region for invalidation.  We batch invalidate regions
+        // below for efficiency.
+        RegionsToInvalidate.push_back(R);
+        continue;
+      }
+      else {
+        // Nuke all other arguments passed by reference.
+        // FIXME: is this necessary or correct? This handles the non-Region
+        //  cases.  Is it ever valid to store to these?
+        state = state->unbindLoc(cast<Loc>(V));
+      }
+    }
+    else if (isa<nonloc::LocAsInteger>(V)) {
+      // If we are passing a location wrapped as an integer, unwrap it and
+      // invalidate the values referred by the location.
+      V = cast<nonloc::LocAsInteger>(V).getLoc();
+      goto tryAgain;
+    }
+  }
+
+  // Block calls result in all captured values passed-via-reference to be
+  // invalidated.
+  if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
+    RegionsToInvalidate.push_back(BR);
+  }
+
+  // Invalidate regions we designed for invalidation use the batch invalidation
+  // API.
+
+  // FIXME: We can have collisions on the conjured symbol if the
+  //  expression *I also creates conjured symbols.  We probably want
+  //  to identify conjured symbols by an expression pair: the enclosing
+  //  expression (the context) and the expression itself.  This should
+  //  disambiguate conjured symbols.
+  unsigned Count = Builder.getCurrentBlockCount();
+  StoreManager::InvalidatedSymbols IS;
+
+  // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
+  //  global variables.
+  state = state->InvalidateRegions(RegionsToInvalidate.data(),
+                                   RegionsToInvalidate.data() +
+                                   RegionsToInvalidate.size(),
+                                   Ex, Count, &IS,
+                                   /* invalidateGlobals = */ true);
+
+  for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
+       E = IS.end(); I!=E; ++I) {
+    SymbolRef sym = *I;
+    if (WhitelistedSymbols.count(sym))
+      continue;
+    // Remove any existing reference-count binding.
+    state = state->remove<RefBindings>(*I);
+  }
+
+  // Evaluate the effect on the message receiver.
+  if (!ErrorRange.isValid() && Receiver) {
+    SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol();
+    if (Sym) {
+      if (const RefVal* T = state->get<RefBindings>(Sym)) {
+        state = Update(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
+        if (hasErr) {
+          ErrorRange = Receiver.getSourceRange();
+          ErrorSym = Sym;
+        }
+      }
+    }
+  }
+
+  // Process any errors.
+  if (hasErr) {
+    ProcessNonLeakError(Dst, Builder, Ex, ErrorRange, Pred, state,
+                        hasErr, ErrorSym);
+    return;
+  }
+
+  // Consult the summary for the return value.
+  RetEffect RE = Summ.getRetEffect();
+
+  if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
+    bool found = false;
+    if (Receiver) {
+      SVal V = Receiver.getSValAsScalarOrLoc(state);
+      if (SymbolRef Sym = V.getAsLocSymbol())
+        if (state->get<RefBindings>(Sym)) {
+          found = true;
+          RE = Summaries.getObjAllocRetEffect();
+        }
+    } // FIXME: Otherwise, this is a send-to-super instance message.
+    if (!found)
+      RE = RetEffect::MakeNoRet();
+  }
+
+  switch (RE.getKind()) {
+    default:
+      assert (false && "Unhandled RetEffect."); break;
+
+    case RetEffect::NoRet: {
+      // Make up a symbol for the return value (not reference counted).
+      // FIXME: Most of this logic is not specific to the retain/release
+      // checker.
+
+      // FIXME: We eventually should handle structs and other compound types
+      // that are returned by value.
+
+      QualType T = Ex->getType();
+
+      // For CallExpr, use the result type to know if it returns a reference.
+      if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) {
+        const Expr *Callee = CE->getCallee();
+        if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl())
+          T = FD->getResultType();
+      }
+      else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
+        if (const ObjCMethodDecl *MD = ME->getMethodDecl())
+          T = MD->getResultType();
+      }
+
+      if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
+        unsigned Count = Builder.getCurrentBlockCount();
+        SValBuilder &svalBuilder = Eng.getSValBuilder();
+        SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, T, Count);
+        state = state->BindExpr(Ex, X, false);
+      }
+
+      break;
+    }
+
+    case RetEffect::Alias: {
+      unsigned idx = RE.getIndex();
+      assert (arg_end >= arg_beg);
+      assert (idx < (unsigned) (arg_end - arg_beg));
+      SVal V = state->getSValAsScalarOrLoc(*(arg_beg+idx));
+      state = state->BindExpr(Ex, V, false);
+      break;
+    }
+
+    case RetEffect::ReceiverAlias: {
+      assert(Receiver);
+      SVal V = Receiver.getSValAsScalarOrLoc(state);
+      state = state->BindExpr(Ex, V, false);
+      break;
+    }
+
+    case RetEffect::OwnedAllocatedSymbol:
+    case RetEffect::OwnedSymbol: {
+      unsigned Count = Builder.getCurrentBlockCount();
+      SValBuilder &svalBuilder = Eng.getSValBuilder();
+      SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
+      QualType RetT = GetReturnType(Ex, svalBuilder.getContext());
+      state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(),
+                                                            RetT));
+      state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
+
+      // FIXME: Add a flag to the checker where allocations are assumed to
+      // *not fail.
+#if 0
+      if (RE.getKind() == RetEffect::OwnedAllocatedSymbol) {
+        bool isFeasible;
+        state = state.assume(loc::SymbolVal(Sym), true, isFeasible);
+        assert(isFeasible && "Cannot assume fresh symbol is non-null.");
+      }
+#endif
+
+      break;
+    }
+
+    case RetEffect::GCNotOwnedSymbol:
+    case RetEffect::NotOwnedSymbol: {
+      unsigned Count = Builder.getCurrentBlockCount();
+      SValBuilder &svalBuilder = Eng.getSValBuilder();
+      SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count);
+      QualType RetT = GetReturnType(Ex, svalBuilder.getContext());
+      state = state->set<RefBindings>(Sym, RefVal::makeNotOwned(RE.getObjKind(),
+                                                               RetT));
+      state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false);
+      break;
+    }
+  }
+
+  // Generate a sink node if we are at the end of a path.
+  ExplodedNode *NewNode =
+    Summ.isEndPath() ? Builder.MakeSinkNode(Dst, Ex, Pred, state)
+                     : Builder.MakeNode(Dst, Ex, Pred, state);
+
+  // Annotate the edge with summary we used.
+  if (NewNode) SummaryLog[NewNode] = &Summ;
+}
+
+
+void CFRefCount::evalCall(ExplodedNodeSet& Dst,
+                          ExprEngine& Eng,
+                          StmtNodeBuilder& Builder,
+                          const CallExpr* CE, SVal L,
+                          ExplodedNode* Pred) {
+
+  RetainSummary *Summ = 0;
+
+  // FIXME: Better support for blocks.  For now we stop tracking anything
+  // that is passed to blocks.
+  // FIXME: Need to handle variables that are "captured" by the block.
+  if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
+    Summ = Summaries.getPersistentStopSummary();
+  }
+  else {
+    const FunctionDecl* FD = L.getAsFunctionDecl();
+    Summ = !FD ? Summaries.getDefaultSummary() :
+                 Summaries.getSummary(FD);
+  }
+
+  assert(Summ);
+  evalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
+              CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
+}
+
+void CFRefCount::evalObjCMessageExpr(ExplodedNodeSet& Dst,
+                                     ExprEngine& Eng,
+                                     StmtNodeBuilder& Builder,
+                                     const ObjCMessageExpr* ME,
+                                     ExplodedNode* Pred,
+                                     const GRState *state) {
+  RetainSummary *Summ =
+    ME->isInstanceMessage()
+      ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
+      : Summaries.getClassMethodSummary(ME);
+
+  assert(Summ && "RetainSummary is null");
+  evalSummary(Dst, Eng, Builder, ME,
+              InstanceReceiver(ME, Pred->getLocationContext()), *Summ, NULL,
+              ME->arg_begin(), ME->arg_end(), Pred, state);
+}
+
+namespace {
+class StopTrackingCallback : public SymbolVisitor {
+  const GRState *state;
+public:
+  StopTrackingCallback(const GRState *st) : state(st) {}
+  const GRState *getState() const { return state; }
+
+  bool VisitSymbol(SymbolRef sym) {
+    state = state->remove<RefBindings>(sym);
+    return true;
+  }
+};
+} // end anonymous namespace
+
+
+void CFRefCount::evalBind(StmtNodeBuilderRef& B, SVal location, SVal val) {
+  // Are we storing to something that causes the value to "escape"?
+  bool escapes = false;
+
+  // A value escapes in three possible cases (this may change):
+  //
+  // (1) we are binding to something that is not a memory region.
+  // (2) we are binding to a memregion that does not have stack storage
+  // (3) we are binding to a memregion with stack storage that the store
+  //     does not understand.
+  const GRState *state = B.getState();
+
+  if (!isa<loc::MemRegionVal>(location))
+    escapes = true;
+  else {
+    const MemRegion* R = cast<loc::MemRegionVal>(location).getRegion();
+    escapes = !R->hasStackStorage();
+
+    if (!escapes) {
+      // To test (3), generate a new state with the binding removed.  If it is
+      // the same state, then it escapes (since the store cannot represent
+      // the binding).
+      escapes = (state == (state->bindLoc(cast<Loc>(location), UnknownVal())));
+    }
+  }
+
+  // If our store can represent the binding and we aren't storing to something
+  // that doesn't have local storage then just return and have the simulation
+  // state continue as is.
+  if (!escapes)
+      return;
+
+  // Otherwise, find all symbols referenced by 'val' that we are tracking
+  // and stop tracking them.
+  B.MakeNode(state->scanReachableSymbols<StopTrackingCallback>(val).getState());
+}
+
+ // Return statements.
+
+void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
+                            ExprEngine& Eng,
+                            StmtNodeBuilder& Builder,
+                            const ReturnStmt* S,
+                            ExplodedNode* Pred) {
+
+  const Expr* RetE = S->getRetValue();
+  if (!RetE)
+    return;
+
+  const GRState *state = Builder.GetState(Pred);
+  SymbolRef Sym = state->getSValAsScalarOrLoc(RetE).getAsLocSymbol();
+
+  if (!Sym)
+    return;
+
+  // Get the reference count binding (if any).
+  const RefVal* T = state->get<RefBindings>(Sym);
+
+  if (!T)
+    return;
+
+  // Change the reference count.
+  RefVal X = *T;
+
+  switch (X.getKind()) {
+    case RefVal::Owned: {
+      unsigned cnt = X.getCount();
+      assert (cnt > 0);
+      X.setCount(cnt - 1);
+      X = X ^ RefVal::ReturnedOwned;
+      break;
+    }
+
+    case RefVal::NotOwned: {
+      unsigned cnt = X.getCount();
+      if (cnt) {
+        X.setCount(cnt - 1);
+        X = X ^ RefVal::ReturnedOwned;
+      }
+      else {
+        X = X ^ RefVal::ReturnedNotOwned;
+      }
+      break;
+    }
+
+    default:
+      return;
+  }
+
+  // Update the binding.
+  state = state->set<RefBindings>(Sym, X);
+  Pred = Builder.MakeNode(Dst, S, Pred, state);
+
+  // Did we cache out?
+  if (!Pred)
+    return;
+
+  // Update the autorelease counts.
+  static unsigned autoreleasetag = 0;
+  GenericNodeBuilder Bd(Builder, S, &autoreleasetag);
+  bool stop = false;
+  llvm::tie(Pred, state) = HandleAutoreleaseCounts(state , Bd, Pred, Eng, Sym,
+                                                   X, stop);
+
+  // Did we cache out?
+  if (!Pred || stop)
+    return;
+
+  // Get the updated binding.
+  T = state->get<RefBindings>(Sym);
+  assert(T);
+  X = *T;
+
+  // Any leaks or other errors?
+  if (X.isReturnedOwned() && X.getCount() == 0) {
+    Decl const *CD = &Pred->getCodeDecl();
+    if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+      const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+      RetEffect RE = Summ.getRetEffect();
+      bool hasError = false;
+
+      if (RE.getKind() != RetEffect::NoRet) {
+        if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
+          // Things are more complicated with garbage collection.  If the
+          // returned object is suppose to be an Objective-C object, we have
+          // a leak (as the caller expects a GC'ed object) because no
+          // method should return ownership unless it returns a CF object.
+          hasError = true;
+          X = X ^ RefVal::ErrorGCLeakReturned;
+        }
+        else if (!RE.isOwned()) {
+          // Either we are using GC and the returned object is a CF type
+          // or we aren't using GC.  In either case, we expect that the
+          // enclosing method is expected to return ownership.
+          hasError = true;
+          X = X ^ RefVal::ErrorLeakReturned;
+        }
+      }
+
+      if (hasError) {
+        // Generate an error node.
+        static int ReturnOwnLeakTag = 0;
+        state = state->set<RefBindings>(Sym, X);
+        ExplodedNode *N =
+          Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
+                                        &ReturnOwnLeakTag), state, Pred);
+        if (N) {
+          CFRefReport *report =
+            new CFRefLeakReport(*static_cast<CFRefBug*>(leakAtReturn), *this,
+                                N, Sym, Eng);
+          BR->EmitReport(report);
+        }
+      }
+    }
+  }
+  else if (X.isReturnedNotOwned()) {
+    Decl const *CD = &Pred->getCodeDecl();
+    if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+      const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+      if (Summ.getRetEffect().isOwned()) {
+        // Trying to return a not owned object to a caller expecting an
+        // owned object.
+
+        static int ReturnNotOwnedForOwnedTag = 0;
+        state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
+        if (ExplodedNode *N =
+            Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
+                                          &ReturnNotOwnedForOwnedTag),
+                                 state, Pred)) {
+            CFRefReport *report =
+                new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
+                                *this, N, Sym);
+            BR->EmitReport(report);
+        }
+      }
+    }
+  }
+}
+
+// Assumptions.
+
+const GRState* CFRefCount::evalAssume(const GRState *state,
+                                      SVal Cond, bool Assumption) {
+
+  // FIXME: We may add to the interface of evalAssume the list of symbols
+  //  whose assumptions have changed.  For now we just iterate through the
+  //  bindings and check if any of the tracked symbols are NULL.  This isn't
+  //  too bad since the number of symbols we will track in practice are
+  //  probably small and evalAssume is only called at branches and a few
+  //  other places.
+  RefBindings B = state->get<RefBindings>();
+
+  if (B.isEmpty())
+    return state;
+
+  bool changed = false;
+  RefBindings::Factory& RefBFactory = state->get_context<RefBindings>();
+
+  for (RefBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+    // Check if the symbol is null (or equal to any constant).
+    // If this is the case, stop tracking the symbol.
+    if (state->getSymVal(I.getKey())) {
+      changed = true;
+      B = RefBFactory.remove(B, I.getKey());
+    }
+  }
+
+  if (changed)
+    state = state->set<RefBindings>(B);
+
+  return state;
+}
+
+const GRState * CFRefCount::Update(const GRState * state, SymbolRef sym,
+                              RefVal V, ArgEffect E,
+                              RefVal::Kind& hasErr) {
+
+  // In GC mode [... release] and [... retain] do nothing.
+  switch (E) {
+    default: break;
+    case IncRefMsg: E = isGCEnabled() ? DoNothing : IncRef; break;
+    case DecRefMsg: E = isGCEnabled() ? DoNothing : DecRef; break;
+    case MakeCollectable: E = isGCEnabled() ? DecRef : DoNothing; break;
+    case NewAutoreleasePool: E = isGCEnabled() ? DoNothing :
+                                                 NewAutoreleasePool; break;
+  }
+
+  // Handle all use-after-releases.
+  if (!isGCEnabled() && V.getKind() == RefVal::Released) {
+    V = V ^ RefVal::ErrorUseAfterRelease;
+    hasErr = V.getKind();
+    return state->set<RefBindings>(sym, V);
+  }
+
+  switch (E) {
+    default:
+      assert (false && "Unhandled CFRef transition.");
+
+    case Dealloc:
+      // Any use of -dealloc in GC is *bad*.
+      if (isGCEnabled()) {
+        V = V ^ RefVal::ErrorDeallocGC;
+        hasErr = V.getKind();
+        break;
+      }
+
+      switch (V.getKind()) {
+        default:
+          assert(false && "Invalid case.");
+        case RefVal::Owned:
+          // The object immediately transitions to the released state.
+          V = V ^ RefVal::Released;
+          V.clearCounts();
+          return state->set<RefBindings>(sym, V);
+        case RefVal::NotOwned:
+          V = V ^ RefVal::ErrorDeallocNotOwned;
+          hasErr = V.getKind();
+          break;
+      }
+      break;
+
+    case NewAutoreleasePool:
+      assert(!isGCEnabled());
+      return state->add<AutoreleaseStack>(sym);
+
+    case MayEscape:
+      if (V.getKind() == RefVal::Owned) {
+        V = V ^ RefVal::NotOwned;
+        break;
+      }
+
+      // Fall-through.
+
+    case DoNothingByRef:
+    case DoNothing:
+      return state;
+
+    case Autorelease:
+      if (isGCEnabled())
+        return state;
+
+      // Update the autorelease counts.
+      state = SendAutorelease(state, ARCountFactory, sym);
+      V = V.autorelease();
+      break;
+
+    case StopTracking:
+      return state->remove<RefBindings>(sym);
+
+    case IncRef:
+      switch (V.getKind()) {
+        default:
+          assert(false);
+
+        case RefVal::Owned:
+        case RefVal::NotOwned:
+          V = V + 1;
+          break;
+        case RefVal::Released:
+          // Non-GC cases are handled above.
+          assert(isGCEnabled());
+          V = (V ^ RefVal::Owned) + 1;
+          break;
+      }
+      break;
+
+    case SelfOwn:
+      V = V ^ RefVal::NotOwned;
+      // Fall-through.
+    case DecRef:
+      switch (V.getKind()) {
+        default:
+          // case 'RefVal::Released' handled above.
+          assert (false);
+
+        case RefVal::Owned:
+          assert(V.getCount() > 0);
+          if (V.getCount() == 1) V = V ^ RefVal::Released;
+          V = V - 1;
+          break;
+
+        case RefVal::NotOwned:
+          if (V.getCount() > 0)
+            V = V - 1;
+          else {
+            V = V ^ RefVal::ErrorReleaseNotOwned;
+            hasErr = V.getKind();
+          }
+          break;
+
+        case RefVal::Released:
+          // Non-GC cases are handled above.
+          assert(isGCEnabled());
+          V = V ^ RefVal::ErrorUseAfterRelease;
+          hasErr = V.getKind();
+          break;
+      }
+      break;
+  }
+  return state->set<RefBindings>(sym, V);
+}
+
+//===----------------------------------------------------------------------===//
+// Handle dead symbols and end-of-path.
+//===----------------------------------------------------------------------===//
+
+std::pair<ExplodedNode*, const GRState *>
+CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd,
+                                    ExplodedNode* Pred,
+                                    ExprEngine &Eng,
+                                    SymbolRef Sym, RefVal V, bool &stop) {
+
+  unsigned ACnt = V.getAutoreleaseCount();
+  stop = false;
+
+  // No autorelease counts?  Nothing to be done.
+  if (!ACnt)
+    return std::make_pair(Pred, state);
+
+  assert(!isGCEnabled() && "Autorelease counts in GC mode?");
+  unsigned Cnt = V.getCount();
+
+  // FIXME: Handle sending 'autorelease' to already released object.
+
+  if (V.getKind() == RefVal::ReturnedOwned)
+    ++Cnt;
+
+  if (ACnt <= Cnt) {
+    if (ACnt == Cnt) {
+      V.clearCounts();
+      if (V.getKind() == RefVal::ReturnedOwned)
+        V = V ^ RefVal::ReturnedNotOwned;
+      else
+        V = V ^ RefVal::NotOwned;
+    }
+    else {
+      V.setCount(Cnt - ACnt);
+      V.setAutoreleaseCount(0);
+    }
+    state = state->set<RefBindings>(Sym, V);
+    ExplodedNode *N = Bd.MakeNode(state, Pred);
+    stop = (N == 0);
+    return std::make_pair(N, state);
+  }
+
+  // Woah!  More autorelease counts then retain counts left.
+  // Emit hard error.
+  stop = true;
+  V = V ^ RefVal::ErrorOverAutorelease;
+  state = state->set<RefBindings>(Sym, V);
+
+  if (ExplodedNode *N = Bd.MakeNode(state, Pred)) {
+    N->markAsSink();
+
+    std::string sbuf;
+    llvm::raw_string_ostream os(sbuf);
+    os << "Object over-autoreleased: object was sent -autorelease";
+    if (V.getAutoreleaseCount() > 1)
+      os << V.getAutoreleaseCount() << " times";
+    os << " but the object has ";
+    if (V.getCount() == 0)
+      os << "zero (locally visible)";
+    else
+      os << "+" << V.getCount();
+    os << " retain counts";
+
+    CFRefReport *report =
+      new CFRefReport(*static_cast<CFRefBug*>(overAutorelease),
+                      *this, N, Sym, os.str());
+    BR->EmitReport(report);
+  }
+
+  return std::make_pair((ExplodedNode*)0, state);
+}
+
+const GRState *
+CFRefCount::HandleSymbolDeath(const GRState * state, SymbolRef sid, RefVal V,
+                              llvm::SmallVectorImpl<SymbolRef> &Leaked) {
+
+  bool hasLeak = V.isOwned() ||
+  ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0);
+
+  if (!hasLeak)
+    return state->remove<RefBindings>(sid);
+
+  Leaked.push_back(sid);
+  return state->set<RefBindings>(sid, V ^ RefVal::ErrorLeak);
+}
+
+ExplodedNode*
+CFRefCount::ProcessLeaks(const GRState * state,
+                         llvm::SmallVectorImpl<SymbolRef> &Leaked,
+                         GenericNodeBuilder &Builder,
+                         ExprEngine& Eng,
+                         ExplodedNode *Pred) {
+
+  if (Leaked.empty())
+    return Pred;
+
+  // Generate an intermediate node representing the leak point.
+  ExplodedNode *N = Builder.MakeNode(state, Pred);
+
+  if (N) {
+    for (llvm::SmallVectorImpl<SymbolRef>::iterator
+         I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
+
+      CFRefBug *BT = static_cast<CFRefBug*>(Pred ? leakWithinFunction
+                                                 : leakAtReturn);
+      assert(BT && "BugType not initialized.");
+      CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng);
+      BR->EmitReport(report);
+    }
+  }
+
+  return N;
+}
+
+void CFRefCount::evalEndPath(ExprEngine& Eng,
+                             EndPathNodeBuilder& Builder) {
+
+  const GRState *state = Builder.getState();
+  GenericNodeBuilder Bd(Builder);
+  RefBindings B = state->get<RefBindings>();
+  ExplodedNode *Pred = 0;
+
+  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+    bool stop = false;
+    llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
+                                                     (*I).first,
+                                                     (*I).second, stop);
+
+    if (stop)
+      return;
+  }
+
+  B = state->get<RefBindings>();
+  llvm::SmallVector<SymbolRef, 10> Leaked;
+
+  for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+    state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked);
+
+  ProcessLeaks(state, Leaked, Bd, Eng, Pred);
+}
+
+void CFRefCount::evalDeadSymbols(ExplodedNodeSet& Dst,
+                                 ExprEngine& Eng,
+                                 StmtNodeBuilder& Builder,
+                                 ExplodedNode* Pred,
+                                 const GRState* state,
+                                 SymbolReaper& SymReaper) {
+  const Stmt *S = Builder.getStmt();
+  RefBindings B = state->get<RefBindings>();
+
+  // Update counts from autorelease pools
+  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+       E = SymReaper.dead_end(); I != E; ++I) {
+    SymbolRef Sym = *I;
+    if (const RefVal* T = B.lookup(Sym)){
+      // Use the symbol as the tag.
+      // FIXME: This might not be as unique as we would like.
+      GenericNodeBuilder Bd(Builder, S, Sym);
+      bool stop = false;
+      llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng,
+                                                       Sym, *T, stop);
+      if (stop)
+        return;
+    }
+  }
+
+  B = state->get<RefBindings>();
+  llvm::SmallVector<SymbolRef, 10> Leaked;
+
+  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+       E = SymReaper.dead_end(); I != E; ++I) {
+      if (const RefVal* T = B.lookup(*I))
+        state = HandleSymbolDeath(state, *I, *T, Leaked);
+  }
+
+  static unsigned LeakPPTag = 0;
+  {
+    GenericNodeBuilder Bd(Builder, S, &LeakPPTag);
+    Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred);
+  }
+
+  // Did we cache out?
+  if (!Pred)
+    return;
+
+  // Now generate a new node that nukes the old bindings.
+  RefBindings::Factory& F = state->get_context<RefBindings>();
+
+  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+       E = SymReaper.dead_end(); I!=E; ++I) B = F.remove(B, *I);
+
+  state = state->set<RefBindings>(B);
+  Builder.MakeNode(Dst, S, Pred, state);
+}
+
+void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
+                                     StmtNodeBuilder& Builder,
+                                     const Expr* NodeExpr, 
+                                     SourceRange ErrorRange,
+                                     ExplodedNode* Pred,
+                                     const GRState* St,
+                                     RefVal::Kind hasErr, SymbolRef Sym) {
+  Builder.BuildSinks = true;
+  ExplodedNode *N  = Builder.MakeNode(Dst, NodeExpr, Pred, St);
+
+  if (!N)
+    return;
+
+  CFRefBug *BT = 0;
+
+  switch (hasErr) {
+    default:
+      assert(false && "Unhandled error.");
+      return;
+    case RefVal::ErrorUseAfterRelease:
+      BT = static_cast<CFRefBug*>(useAfterRelease);
+      break;
+    case RefVal::ErrorReleaseNotOwned:
+      BT = static_cast<CFRefBug*>(releaseNotOwned);
+      break;
+    case RefVal::ErrorDeallocGC:
+      BT = static_cast<CFRefBug*>(deallocGC);
+      break;
+    case RefVal::ErrorDeallocNotOwned:
+      BT = static_cast<CFRefBug*>(deallocNotOwned);
+      break;
+  }
+
+  CFRefReport *report = new CFRefReport(*BT, *this, N, Sym);
+  report->addRange(ErrorRange);
+  BR->EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
+// Pieces of the retain/release checker implemented using a CheckerVisitor.
+// More pieces of the retain/release checker will be migrated to this interface
+// (ideally, all of it some day).
+//===----------------------------------------------------------------------===//
+
+namespace {
+class RetainReleaseChecker
+  : public CheckerVisitor<RetainReleaseChecker> {
+  CFRefCount *TF;
+public:
+    RetainReleaseChecker(CFRefCount *tf) : TF(tf) {}
+    static void* getTag() { static int x = 0; return &x; }
+
+    void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+};
+} // end anonymous namespace
+
+
+void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C,
+                                              const BlockExpr *BE) {
+
+  // Scan the BlockDecRefExprs for any object the retain/release checker
+  // may be tracking.
+  if (!BE->hasBlockDeclRefExprs())
+    return;
+
+  const GRState *state = C.getState();
+  const BlockDataRegion *R =
+    cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+  BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+                                            E = R->referenced_vars_end();
+
+  if (I == E)
+    return;
+
+  // FIXME: For now we invalidate the tracking of all symbols passed to blocks
+  // via captured variables, even though captured variables result in a copy
+  // and in implicit increment/decrement of a retain count.
+  llvm::SmallVector<const MemRegion*, 10> Regions;
+  const LocationContext *LC = C.getPredecessor()->getLocationContext();
+  MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
+
+  for ( ; I != E; ++I) {
+    const VarRegion *VR = *I;
+    if (VR->getSuperRegion() == R) {
+      VR = MemMgr.getVarRegion(VR->getDecl(), LC);
+    }
+    Regions.push_back(VR);
+  }
+
+  state =
+    state->scanReachableSymbols<StopTrackingCallback>(Regions.data(),
+                                    Regions.data() + Regions.size()).getState();
+  C.addTransition(state);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function creation for external clients.
+//===----------------------------------------------------------------------===//
+
+void CFRefCount::RegisterChecks(ExprEngine& Eng) {
+  BugReporter &BR = Eng.getBugReporter();
+
+  useAfterRelease = new UseAfterRelease(this);
+  BR.Register(useAfterRelease);
+
+  releaseNotOwned = new BadRelease(this);
+  BR.Register(releaseNotOwned);
+
+  deallocGC = new DeallocGC(this);
+  BR.Register(deallocGC);
+
+  deallocNotOwned = new DeallocNotOwned(this);
+  BR.Register(deallocNotOwned);
+
+  overAutorelease = new OverAutorelease(this);
+  BR.Register(overAutorelease);
+
+  returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
+  BR.Register(returnNotOwnedForOwned);
+
+  // First register "return" leaks.
+  const char* name = 0;
+
+  if (isGCEnabled())
+    name = "Leak of returned object when using garbage collection";
+  else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+    name = "Leak of returned object when not using garbage collection (GC) in "
+    "dual GC/non-GC code";
+  else {
+    assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+    name = "Leak of returned object";
+  }
+
+  // Leaks should not be reported if they are post-dominated by a sink.
+  leakAtReturn = new LeakAtReturn(this, name);
+  leakAtReturn->setSuppressOnSink(true);
+  BR.Register(leakAtReturn);
+
+  // Second, register leaks within a function/method.
+  if (isGCEnabled())
+    name = "Leak of object when using garbage collection";
+  else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+    name = "Leak of object when not using garbage collection (GC) in "
+    "dual GC/non-GC code";
+  else {
+    assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+    name = "Leak";
+  }
+
+  // Leaks should not be reported if they are post-dominated by sinks.
+  leakWithinFunction = new LeakWithinFunction(this, name);
+  leakWithinFunction->setSuppressOnSink(true);
+  BR.Register(leakWithinFunction);
+
+  // Save the reference to the BugReporter.
+  this->BR = &BR;
+
+  // Register the RetainReleaseChecker with the ExprEngine object.
+  // Functionality in CFRefCount will be migrated to RetainReleaseChecker
+  // over time.
+  Eng.registerCheck(new RetainReleaseChecker(this));
+}
+
+TransferFuncs* ento::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+                                         const LangOptions& lopts) {
+  return new CFRefCount(Ctx, GCEnabled, lopts);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/CMakeLists.txt b/lib/StaticAnalyzer/EntoSA/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cf81e1d
--- /dev/null
@@ -0,0 +1,41 @@
+set(LLVM_NO_RTTI 1)
+
+set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
+
+add_clang_library(clangStaticAnalyzerCore
+  AggExprVisitor.cpp
+  AnalysisManager.cpp
+  AnalyzerStatsChecker.cpp
+  BasicConstraintManager.cpp
+  BasicStore.cpp
+  BasicValueFactory.cpp
+  BugReporter.cpp
+  BugReporterVisitors.cpp
+  CFRefCount.cpp
+  Checker.cpp
+  CheckerHelpers.cpp
+  Environment.cpp
+  ExplodedGraph.cpp
+  FlatStore.cpp
+  BlockCounter.cpp
+  CXXExprEngine.cpp
+  CoreEngine.cpp
+  GRState.cpp
+  HTMLDiagnostics.cpp
+  ManagerRegistry.cpp
+  MemRegion.cpp
+  PathDiagnostic.cpp
+  PlistDiagnostics.cpp
+  RangeConstraintManager.cpp
+  RegionStore.cpp
+  SimpleConstraintManager.cpp
+  SimpleSValBuilder.cpp
+  Store.cpp
+  SValBuilder.cpp
+  SVals.cpp
+  SymbolManager.cpp
+  TextPathDiagnostics.cpp
+  )
+
+add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
+                 ClangStmtNodes)
diff --git a/lib/StaticAnalyzer/EntoSA/CXXExprEngine.cpp b/lib/StaticAnalyzer/EntoSA/CXXExprEngine.cpp
new file mode 100644 (file)
index 0000000..47b3a0b
--- /dev/null
@@ -0,0 +1,328 @@
+//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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 C++ expression evaluation engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class CallExprWLItem {
+public:
+  CallExpr::const_arg_iterator I;
+  ExplodedNode *N;
+
+  CallExprWLItem(const CallExpr::const_arg_iterator &i, ExplodedNode *n)
+    : I(i), N(n) {}
+};
+}
+
+void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE,
+                                 const FunctionProtoType *FnType, 
+                                 ExplodedNode *Pred, ExplodedNodeSet &Dst,
+                                 bool FstArgAsLValue) {
+
+
+  llvm::SmallVector<CallExprWLItem, 20> WorkList;
+  WorkList.reserve(AE - AI);
+  WorkList.push_back(CallExprWLItem(AI, Pred));
+
+  while (!WorkList.empty()) {
+    CallExprWLItem Item = WorkList.back();
+    WorkList.pop_back();
+
+    if (Item.I == AE) {
+      Dst.insert(Item.N);
+      continue;
+    }
+
+    // Evaluate the argument.
+    ExplodedNodeSet Tmp;
+    bool VisitAsLvalue = FstArgAsLValue;
+    if (FstArgAsLValue) {
+      FstArgAsLValue = false;
+    } else {
+      const unsigned ParamIdx = Item.I - AI;
+      VisitAsLvalue = FnType && ParamIdx < FnType->getNumArgs() 
+        ? FnType->getArgType(ParamIdx)->isReferenceType()
+        : false;
+    }
+
+    Visit(*Item.I, Item.N, Tmp);
+    ++(Item.I);
+    for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
+      WorkList.push_back(CallExprWLItem(Item.I, *NI));
+  }
+}
+
+const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D,
+                                                 const StackFrameContext *SFC) {
+  Type *T = D->getTypeForDecl();
+  QualType PT = getContext().getPointerType(QualType(T, 0));
+  return svalBuilder.getRegionManager().getCXXThisRegion(PT, SFC);
+}
+
+const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl,
+                                            const StackFrameContext *frameCtx) {
+  return svalBuilder.getRegionManager().
+                    getCXXThisRegion(decl->getThisType(getContext()), frameCtx);
+}
+
+void ExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred,
+                                            ExplodedNodeSet &Dst) {
+  ExplodedNodeSet Tmp;
+  Visit(Ex, Pred, Tmp);
+  for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+    const GRState *state = GetState(*I);
+
+    // Bind the temporary object to the value of the expression. Then bind
+    // the expression to the location of the object.
+    SVal V = state->getSVal(Ex);
+
+    const MemRegion *R =
+      svalBuilder.getRegionManager().getCXXTempObjectRegion(Ex,
+                                                   Pred->getLocationContext());
+
+    state = state->bindLoc(loc::MemRegionVal(R), V);
+    MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
+  }
+}
+
+void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, 
+                                         const MemRegion *Dest,
+                                         ExplodedNode *Pred,
+                                         ExplodedNodeSet &Dst) {
+  if (!Dest)
+    Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
+                                                    Pred->getLocationContext());
+
+  if (E->isElidable()) {
+    VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
+    return;
+  }
+
+  const CXXConstructorDecl *CD = E->getConstructor();
+  assert(CD);
+
+  if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+    // FIXME: invalidate the object.
+    return;
+
+  
+  // Evaluate other arguments.
+  ExplodedNodeSet argsEvaluated;
+  const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
+  evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
+  // The callee stack frame context used to create the 'this' parameter region.
+  const StackFrameContext *SFC = AMgr.getStackFrame(CD, 
+                                                    Pred->getLocationContext(),
+                                                    E, Builder->getBlock(),
+                                                    Builder->getIndex());
+
+  const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(),
+                                               SFC);
+
+  CallEnter Loc(E, SFC, Pred->getLocationContext());
+  for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
+                                 NE = argsEvaluated.end(); NI != NE; ++NI) {
+    const GRState *state = GetState(*NI);
+    // Setup 'this' region, so that the ctor is evaluated on the object pointed
+    // by 'Dest'.
+    state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
+    ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+    if (N)
+      Dst.Add(N);
+  }
+}
+
+void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
+                                      const MemRegion *Dest,
+                                      const Stmt *S,
+                                      ExplodedNode *Pred, 
+                                      ExplodedNodeSet &Dst) {
+  if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+    return;
+  // Create the context for 'this' region.
+  const StackFrameContext *SFC = AMgr.getStackFrame(DD,
+                                                    Pred->getLocationContext(),
+                                                    S, Builder->getBlock(),
+                                                    Builder->getIndex());
+
+  const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC);
+
+  CallEnter PP(S, SFC, Pred->getLocationContext());
+
+  const GRState *state = Pred->getState();
+  state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
+  ExplodedNode *N = Builder->generateNode(PP, state, Pred);
+  if (N)
+    Dst.Add(N);
+}
+
+void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, 
+                                          ExplodedNode *Pred, 
+                                          ExplodedNodeSet &Dst) {
+  // Get the method type.
+  const FunctionProtoType *FnType = 
+                       MCE->getCallee()->getType()->getAs<FunctionProtoType>();
+  assert(FnType && "Method type not available");
+
+  // Evaluate explicit arguments with a worklist.
+  ExplodedNodeSet argsEvaluated;
+  evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated);
+  // Evaluate the implicit object argument.
+  ExplodedNodeSet AllargsEvaluated;
+  const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
+  if (!ME)
+    return;
+  Expr *ObjArgExpr = ME->getBase();
+  for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 
+                                 E = argsEvaluated.end(); I != E; ++I) {
+      Visit(ObjArgExpr, *I, AllargsEvaluated);
+  }
+
+  // Now evaluate the call itself.
+  const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+  assert(MD && "not a CXXMethodDecl?");
+  evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst);
+}
+
+void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C,
+                                            ExplodedNode *Pred,
+                                            ExplodedNodeSet &Dst) {
+  const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl());
+  if (!MD) {
+    // If the operator doesn't represent a method call treat as regural call.
+    VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+    return;
+  }
+
+  // Determine the type of function we're calling (if available).
+  const FunctionProtoType *Proto = NULL;
+  QualType FnType = C->getCallee()->IgnoreParens()->getType();
+  if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
+    Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
+
+  // Evaluate arguments treating the first one (object method is called on)
+  // as alvalue.
+  ExplodedNodeSet argsEvaluated;
+  evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true);
+
+  // Now evaluate the call itself.
+  evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst);
+}
+
+void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD,
+                                  const Expr *ThisExpr, ExplodedNode *Pred,
+                                  ExplodedNodeSet &Src, ExplodedNodeSet &Dst) {
+  // Allow checkers to pre-visit the member call.
+  ExplodedNodeSet PreVisitChecks;
+  CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback);
+
+  if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) {
+    // FIXME: conservative method call evaluation.
+    CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback);
+    return;
+  }
+
+  const StackFrameContext *SFC = AMgr.getStackFrame(MD, 
+                                                    Pred->getLocationContext(),
+                                                    MCE,
+                                                    Builder->getBlock(), 
+                                                    Builder->getIndex());
+  const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
+  CallEnter Loc(MCE, SFC, Pred->getLocationContext());
+  for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(),
+         E = PreVisitChecks.end(); I != E; ++I) {
+    // Set up 'this' region.
+    const GRState *state = GetState(*I);
+    state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr));
+    Dst.Add(Builder->generateNode(Loc, state, *I));
+  }
+}
+
+void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
+                                   ExplodedNodeSet &Dst) {
+  if (CNE->isArray()) {
+    // FIXME: allocating an array has not been handled.
+    return;
+  }
+
+  unsigned Count = Builder->getCurrentBlockCount();
+  DefinedOrUnknownSVal symVal =
+    svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), Count);
+  const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
+
+  QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
+
+  const ElementRegion *EleReg = 
+                         getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+
+  // Evaluate constructor arguments.
+  const FunctionProtoType *FnType = NULL;
+  const CXXConstructorDecl *CD = CNE->getConstructor();
+  if (CD)
+    FnType = CD->getType()->getAs<FunctionProtoType>();
+  ExplodedNodeSet argsEvaluated;
+  evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
+                FnType, Pred, argsEvaluated);
+
+  // Initialize the object region and bind the 'new' expression.
+  for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), 
+                                 E = argsEvaluated.end(); I != E; ++I) {
+    const GRState *state = GetState(*I);
+
+    if (ObjTy->isRecordType()) {
+      state = state->InvalidateRegion(EleReg, CNE, Count);
+    } else {
+      if (CNE->hasInitializer()) {
+        SVal V = state->getSVal(*CNE->constructor_arg_begin());
+        state = state->bindLoc(loc::MemRegionVal(EleReg), V);
+      } else {
+        // Explicitly set to undefined, because currently we retrieve symbolic
+        // value from symbolic region.
+        state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
+      }
+    }
+    state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+    MakeNode(Dst, CNE, *I, state);
+  }
+}
+
+void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, 
+                                      ExplodedNode *Pred,ExplodedNodeSet &Dst) {
+  // Should do more checking.
+  ExplodedNodeSet Argevaluated;
+  Visit(CDE->getArgument(), Pred, Argevaluated);
+  for (ExplodedNodeSet::iterator I = Argevaluated.begin(), 
+                                 E = Argevaluated.end(); I != E; ++I) {
+    const GRState *state = GetState(*I);
+    MakeNode(Dst, CDE, *I, state);
+  }
+}
+
+void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
+                                    ExplodedNodeSet &Dst) {
+  // Get the this object region from StoreManager.
+  const MemRegion *R =
+    svalBuilder.getRegionManager().getCXXThisRegion(
+                                  getContext().getCanonicalType(TE->getType()),
+                                               Pred->getLocationContext());
+
+  const GRState *state = GetState(Pred);
+  SVal V = state->getSVal(loc::MemRegionVal(R));
+  MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checker.cpp b/lib/StaticAnalyzer/EntoSA/Checker.cpp
new file mode 100644 (file)
index 0000000..6867ff5
--- /dev/null
@@ -0,0 +1,36 @@
+//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating
+//  domain-specific checks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+using namespace clang;
+using namespace ento;
+
+Checker::~Checker() {}
+
+CheckerContext::~CheckerContext() {
+  // Do we need to autotransition?  'Dst' can get populated in a variety of
+  // ways, including 'addTransition()' adding the predecessor node to Dst
+  // without actually generated a new node.  We also shouldn't autotransition
+  // if we are building sinks or we generated a node and decided to not
+  // add it as a transition.
+  if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) {
+    if (ST && ST != B.GetState(Pred)) {
+      static int autoTransitionTag = 0;
+      B.Tag = &autoTransitionTag;
+      addTransition(ST);
+    }
+    else
+      Dst.Add(Pred);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/CheckerHelpers.cpp b/lib/StaticAnalyzer/EntoSA/CheckerHelpers.cpp
new file mode 100644 (file)
index 0000000..be9fee5
--- /dev/null
@@ -0,0 +1,80 @@
+//===---- CheckerHelpers.cpp - Helper functions for checkers ----*- 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 several static functions for use in checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
+#include "clang/AST/Expr.h"
+
+// Recursively find any substatements containing macros
+bool clang::ento::containsMacro(const Stmt *S) {
+  if (S->getLocStart().isMacroID())
+    return true;
+
+  if (S->getLocEnd().isMacroID())
+    return true;
+
+  for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+      ++I)
+    if (const Stmt *child = *I)
+      if (containsMacro(child))
+        return true;
+
+  return false;
+}
+
+// Recursively find any substatements containing enum constants
+bool clang::ento::containsEnum(const Stmt *S) {
+  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
+
+  if (DR && isa<EnumConstantDecl>(DR->getDecl()))
+    return true;
+
+  for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+      ++I)
+    if (const Stmt *child = *I)
+      if (containsEnum(child))
+        return true;
+
+  return false;
+}
+
+// Recursively find any substatements containing static vars
+bool clang::ento::containsStaticLocal(const Stmt *S) {
+  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
+
+  if (DR)
+    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+      if (VD->isStaticLocal())
+        return true;
+
+  for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+      ++I)
+    if (const Stmt *child = *I)
+      if (containsStaticLocal(child))
+        return true;
+
+  return false;
+}
+
+// Recursively find any substatements containing __builtin_offsetof
+bool clang::ento::containsBuiltinOffsetOf(const Stmt *S) {
+  if (isa<OffsetOfExpr>(S))
+    return true;
+
+  for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+      ++I)
+    if (const Stmt *child = *I)
+      if (containsBuiltinOffsetOf(child))
+        return true;
+
+  return false;
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp
new file mode 100644 (file)
index 0000000..46e2de5
--- /dev/null
@@ -0,0 +1,96 @@
+//== AdjustedReturnValueChecker.cpp -----------------------------*- 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 AdjustedReturnValueChecker, a simple check to see if the
+// return value of a function call is different than the one the caller thinks
+// it is.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class AdjustedReturnValueChecker : 
+    public CheckerVisitor<AdjustedReturnValueChecker> {      
+public:
+  AdjustedReturnValueChecker() {}
+
+  void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+      
+  static void *getTag() {
+    static int x = 0; return &x;
+  }      
+};
+}
+
+void ento::RegisterAdjustedReturnValueChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new AdjustedReturnValueChecker());
+}
+
+void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
+                                                   const CallExpr *CE) {
+  
+  // Get the result type of the call.
+  QualType expectedResultTy = CE->getType();
+
+  // Fetch the signature of the called function.
+  const GRState *state = C.getState();
+
+  SVal V = state->getSVal(CE);
+  
+  if (V.isUnknown())
+    return;
+  
+  // Casting to void?  Discard the value.
+  if (expectedResultTy->isVoidType()) {
+    C.generateNode(state->BindExpr(CE, UnknownVal()));
+    return;
+  }                   
+
+  const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
+  if (!callee)
+    return;
+
+  QualType actualResultTy;
+  
+  if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
+    const FunctionDecl *FD = FT->getDecl();
+    actualResultTy = FD->getResultType();
+  }
+  else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
+    const BlockTextRegion *BR = BD->getCodeRegion();
+    const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
+    const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+    actualResultTy = FT->getResultType();
+  }
+
+  // Can this happen?
+  if (actualResultTy.isNull())
+    return;
+
+  // For now, ignore references.
+  if (actualResultTy->getAs<ReferenceType>())
+    return;
+  
+
+  // Are they the same?
+  if (expectedResultTy != actualResultTy) {
+    // FIXME: Do more checking and actual emit an error. At least performing
+    // the cast avoids some assertion failures elsewhere.
+    SValBuilder &svalBuilder = C.getSValBuilder();
+    V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
+    C.generateNode(state->BindExpr(CE, V));
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp
new file mode 100644 (file)
index 0000000..ee4eae2
--- /dev/null
@@ -0,0 +1,610 @@
+//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// "Meta" ASTConsumer for running different source analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/AnalysisConsumer.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/ManagerRegistry.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+
+// FIXME: Restructure checker registration.
+#include "ExprEngineExperimentalChecks.h"
+#include "ExprEngineInternalChecks.h"
+
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/AnalyzerOptions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/ADT/OwningPtr.h"
+
+using namespace clang;
+using namespace ento;
+
+static ExplodedNode::Auditor* CreateUbiViz();
+
+//===----------------------------------------------------------------------===//
+// Special PathDiagnosticClients.
+//===----------------------------------------------------------------------===//
+
+static PathDiagnosticClient*
+createPlistHTMLDiagnosticClient(const std::string& prefix,
+                                const Preprocessor &PP) {
+  PathDiagnosticClient *PD =
+    createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP);
+  return createPlistDiagnosticClient(prefix, PP, PD);
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer declaration.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class AnalysisConsumer : public ASTConsumer {
+public:
+  typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
+  typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
+                           TranslationUnitDecl &TU);
+
+private:
+  typedef std::vector<CodeAction> Actions;
+  typedef std::vector<TUAction> TUActions;
+
+  Actions FunctionActions;
+  Actions ObjCMethodActions;
+  Actions ObjCImplementationActions;
+  Actions CXXMethodActions;
+  TUActions TranslationUnitActions; // Remove this.
+
+public:
+  ASTContext* Ctx;
+  const Preprocessor &PP;
+  const std::string OutDir;
+  AnalyzerOptions Opts;
+
+  // PD is owned by AnalysisManager.
+  PathDiagnosticClient *PD;
+
+  StoreManagerCreator CreateStoreMgr;
+  ConstraintManagerCreator CreateConstraintMgr;
+
+  llvm::OwningPtr<AnalysisManager> Mgr;
+
+  AnalysisConsumer(const Preprocessor& pp,
+                   const std::string& outdir,
+                   const AnalyzerOptions& opts)
+    : Ctx(0), PP(pp), OutDir(outdir),
+      Opts(opts), PD(0) {
+    DigestAnalyzerOptions();
+  }
+
+  void DigestAnalyzerOptions() {
+    // Create the PathDiagnosticClient.
+    if (!OutDir.empty()) {
+      switch (Opts.AnalysisDiagOpt) {
+      default:
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
+        case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
+#include "clang/Frontend/Analyses.def"
+      }
+    } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
+      // Create the text client even without a specified output file since
+      // it just uses diagnostic notes.
+      PD = createTextPathDiagnosticClient("", PP);
+    }
+
+    // Create the analyzer component creators.
+    if (ManagerRegistry::StoreMgrCreator != 0) {
+      CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
+    }
+    else {
+      switch (Opts.AnalysisStoreOpt) {
+      default:
+        assert(0 && "Unknown store manager.");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN)           \
+        case NAME##Model: CreateStoreMgr = CREATEFN; break;
+#include "clang/Frontend/Analyses.def"
+      }
+    }
+
+    if (ManagerRegistry::ConstraintMgrCreator != 0)
+      CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
+    else {
+      switch (Opts.AnalysisConstraintsOpt) {
+      default:
+        assert(0 && "Unknown store manager.");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN)     \
+        case NAME##Model: CreateConstraintMgr = CREATEFN; break;
+#include "clang/Frontend/Analyses.def"
+      }
+    }
+  }
+
+  void DisplayFunction(const Decl *D) {
+    if (!Opts.AnalyzerDisplayProgress)
+      return;
+
+    SourceManager &SM = Mgr->getASTContext().getSourceManager();
+    PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
+    if (Loc.isValid()) {
+      llvm::errs() << "ANALYZE: " << Loc.getFilename();
+
+      if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+        const NamedDecl *ND = cast<NamedDecl>(D);
+        llvm::errs() << ' ' << ND << '\n';
+      }
+      else if (isa<BlockDecl>(D)) {
+        llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
+                     << Loc.getColumn() << '\n';
+      }
+      else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+        Selector S = MD->getSelector();
+        llvm::errs() << ' ' << S.getAsString();
+      }
+    }
+  }
+
+  void addCodeAction(CodeAction action) {
+    FunctionActions.push_back(action);
+    ObjCMethodActions.push_back(action);
+    CXXMethodActions.push_back(action);
+  }
+
+  void addTranslationUnitAction(TUAction action) {
+    TranslationUnitActions.push_back(action);
+  }
+
+  void addObjCImplementationAction(CodeAction action) {
+    ObjCImplementationActions.push_back(action);
+  }
+
+  virtual void Initialize(ASTContext &Context) {
+    Ctx = &Context;
+    Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
+                                  PP.getLangOptions(), PD,
+                                  CreateStoreMgr, CreateConstraintMgr,
+                                  /* Indexer */ 0, 
+                                  Opts.MaxNodes, Opts.MaxLoop,
+                                  Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
+                                  Opts.PurgeDead, Opts.EagerlyAssume,
+                                  Opts.TrimGraph, Opts.InlineCall,
+                                  Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
+                                  Opts.CFGAddInitializers));
+  }
+
+  virtual void HandleTranslationUnit(ASTContext &C);
+  void HandleCode(Decl *D, Actions& actions);
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer implementation.
+//===----------------------------------------------------------------------===//
+
+void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+
+  TranslationUnitDecl *TU = C.getTranslationUnitDecl();
+
+  for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
+       I != E; ++I) {
+    Decl *D = *I;
+
+    switch (D->getKind()) {
+    case Decl::CXXConstructor:
+    case Decl::CXXDestructor:
+    case Decl::CXXConversion:
+    case Decl::CXXMethod:
+    case Decl::Function: {
+      FunctionDecl* FD = cast<FunctionDecl>(D);
+      // We skip function template definitions, as their semantics is
+      // only determined when they are instantiated.
+      if (FD->isThisDeclarationADefinition() &&
+          !FD->isDependentContext()) {
+        if (!Opts.AnalyzeSpecificFunction.empty() &&
+            FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
+          break;
+        DisplayFunction(FD);
+        HandleCode(FD, FunctionActions);
+      }
+      break;
+    }
+
+    case Decl::ObjCImplementation: {
+      ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
+      HandleCode(ID, ObjCImplementationActions);
+
+      for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), 
+             ME = ID->meth_end(); MI != ME; ++MI) {
+        if ((*MI)->isThisDeclarationADefinition()) {
+          if (!Opts.AnalyzeSpecificFunction.empty() &&
+             Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
+            break;
+          DisplayFunction(*MI);
+          HandleCode(*MI, ObjCMethodActions);
+        }
+      }
+      break;
+    }
+
+    default:
+      break;
+    }
+  }
+
+  for (TUActions::iterator I = TranslationUnitActions.begin(),
+                           E = TranslationUnitActions.end(); I != E; ++I) {
+    (*I)(*this, *Mgr, *TU);
+  }
+
+  // Explicitly destroy the PathDiagnosticClient.  This will flush its output.
+  // FIXME: This should be replaced with something that doesn't rely on
+  // side-effects in PathDiagnosticClient's destructor. This is required when
+  // used with option -disable-free.
+  Mgr.reset(NULL);
+}
+
+static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
+  if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
+    WL.push_back(BD);
+
+  for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
+       I!=E; ++I)
+    if (DeclContext *DC = dyn_cast<DeclContext>(*I))
+      FindBlocks(DC, WL);
+}
+
+void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
+
+  // Don't run the actions if an error has occured with parsing the file.
+  Diagnostic &Diags = PP.getDiagnostics();
+  if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
+    return;
+
+  // Don't run the actions on declarations in header files unless
+  // otherwise specified.
+  SourceManager &SM = Ctx->getSourceManager();
+  SourceLocation SL = SM.getInstantiationLoc(D->getLocation());
+  if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
+    return;
+
+  // Clear the AnalysisManager of old AnalysisContexts.
+  Mgr->ClearContexts();
+
+  // Dispatch on the actions.
+  llvm::SmallVector<Decl*, 10> WL;
+  WL.push_back(D);
+
+  if (D->hasBody() && Opts.AnalyzeNestedBlocks)
+    FindBlocks(cast<DeclContext>(D), WL);
+
+  for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
+    for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
+         WI != WE; ++WI)
+      (*I)(*this, *Mgr, *WI);
+}
+
+//===----------------------------------------------------------------------===//
+// Analyses
+//===----------------------------------------------------------------------===//
+
+static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
+                                 Decl *D) {
+  if (LiveVariables *L = mgr.getLiveVariables(D)) {
+    BugReporter BR(mgr);
+    CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
+  }
+}
+
+static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
+                                 Decl *D) {
+  if (CFG* c = mgr.getCFG(D)) {
+    CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
+  }
+}
+
+
+static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
+                               Decl *D,
+                               TransferFuncs* tf) {
+
+  llvm::OwningPtr<TransferFuncs> TF(tf);
+
+  // Construct the analysis engine.  We first query for the LiveVariables
+  // information to see if the CFG is valid.
+  // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
+  if (!mgr.getLiveVariables(D))
+    return;
+  ExprEngine Eng(mgr, TF.take());
+
+  if (C.Opts.EnableExperimentalInternalChecks)
+    RegisterExperimentalInternalChecks(Eng);
+
+  RegisterAppleChecks(Eng, *D);
+
+  if (C.Opts.EnableExperimentalChecks)
+    RegisterExperimentalChecks(Eng);
+
+  // Enable idempotent operation checking if it was explicitly turned on, or if
+  // we are running experimental checks (i.e. everything)
+  if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks
+      || C.Opts.EnableExperimentalInternalChecks)
+    RegisterIdempotentOperationChecker(Eng);
+  
+  if (C.Opts.BufferOverflows)
+    RegisterArrayBoundCheckerV2(Eng);
+
+  // Enable AnalyzerStatsChecker if it was given as an argument
+  if (C.Opts.AnalyzerStats)
+    RegisterAnalyzerStatsChecker(Eng);
+
+  // Set the graph auditor.
+  llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
+  if (mgr.shouldVisualizeUbigraph()) {
+    Auditor.reset(CreateUbiViz());
+    ExplodedNode::SetAuditor(Auditor.get());
+  }
+
+  // Execute the worklist algorithm.
+  Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes());
+
+  // Release the auditor (if any) so that it doesn't monitor the graph
+  // created BugReporter.
+  ExplodedNode::SetAuditor(0);
+
+  // Visualize the exploded graph.
+  if (mgr.shouldVisualizeGraphviz())
+    Eng.ViewGraph(mgr.shouldTrimGraph());
+
+  // Display warnings.
+  Eng.getBugReporter().FlushReports();
+}
+
+static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
+                                  Decl *D, bool GCEnabled) {
+
+  TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
+                                         GCEnabled,
+                                         mgr.getLangOptions());
+
+  ActionExprEngine(C, mgr, D, TF);
+}
+
+static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
+                               Decl *D) {
+
+ switch (mgr.getLangOptions().getGCMode()) {
+ default:
+   assert (false && "Invalid GC mode.");
+ case LangOptions::NonGC:
+   ActionObjCMemCheckerAux(C, mgr, D, false);
+   break;
+
+ case LangOptions::GCOnly:
+   ActionObjCMemCheckerAux(C, mgr, D, true);
+   break;
+
+ case LangOptions::HybridGC:
+   ActionObjCMemCheckerAux(C, mgr, D, false);
+   ActionObjCMemCheckerAux(C, mgr, D, true);
+   break;
+ }
+}
+
+static void ActionDisplayLiveVariables(AnalysisConsumer &C,
+                                       AnalysisManager& mgr, Decl *D) {
+  if (LiveVariables* L = mgr.getLiveVariables(D)) {
+    L->dumpBlockLiveness(mgr.getSourceManager());
+  }
+}
+
+static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
+  if (CFG *cfg = mgr.getCFG(D)) {
+    cfg->dump(mgr.getLangOptions());
+  }
+}
+
+static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
+  if (CFG *cfg = mgr.getCFG(D)) {
+    cfg->viewCFG(mgr.getLangOptions());
+  }
+}
+
+static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
+                                          AnalysisManager &mgr, Decl *D) {
+  BugReporter BR(mgr);
+  CheckSecuritySyntaxOnly(D, BR);
+}
+
+static void ActionLLVMConventionChecker(AnalysisConsumer &C,
+                                        AnalysisManager &mgr,
+                                        TranslationUnitDecl &TU) {
+  BugReporter BR(mgr);
+  CheckLLVMConventions(TU, BR);
+}
+
+static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
+                                  Decl *D) {
+  if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
+    return;
+  BugReporter BR(mgr);
+  CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
+}
+
+static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
+                                      Decl *D) {
+  BugReporter BR(mgr);
+  CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
+}
+
+static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
+                                   Decl *D) {
+  BugReporter BR(mgr);
+  CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
+}
+
+static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
+                                    Decl *D) {
+  BugReporter BR(mgr);
+  CheckSizeofPointer(D, BR);
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer creation.
+//===----------------------------------------------------------------------===//
+
+ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
+                                           const std::string& OutDir,
+                                           const AnalyzerOptions& Opts) {
+  llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
+
+  for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
+    switch (Opts.AnalysisList[i]) {
+#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
+    case NAME:\
+      C->add ## SCOPE ## Action(&Action ## NAME);\
+      break;
+#include "clang/Frontend/Analyses.def"
+    default: break;
+    }
+
+  // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
+  pp.getDiagnostics().setWarningsAsErrors(false);
+
+  return C.take();
+}
+
+//===----------------------------------------------------------------------===//
+// Ubigraph Visualization.  FIXME: Move to separate file.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class UbigraphViz : public ExplodedNode::Auditor {
+  llvm::OwningPtr<llvm::raw_ostream> Out;
+  llvm::sys::Path Dir, Filename;
+  unsigned Cntr;
+
+  typedef llvm::DenseMap<void*,unsigned> VMap;
+  VMap M;
+
+public:
+  UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+              llvm::sys::Path& filename);
+
+  ~UbigraphViz();
+
+  virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
+};
+
+} // end anonymous namespace
+
+static ExplodedNode::Auditor* CreateUbiViz() {
+  std::string ErrMsg;
+
+  llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
+  if (!ErrMsg.empty())
+    return 0;
+
+  llvm::sys::Path Filename = Dir;
+  Filename.appendComponent("llvm_ubi");
+  Filename.makeUnique(true,&ErrMsg);
+
+  if (!ErrMsg.empty())
+    return 0;
+
+  llvm::errs() << "Writing '" << Filename.str() << "'.\n";
+
+  llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
+  Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
+
+  if (!ErrMsg.empty())
+    return 0;
+
+  return new UbigraphViz(Stream.take(), Dir, Filename);
+}
+
+void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
+
+  assert (Src != Dst && "Self-edges are not allowed.");
+
+  // Lookup the Src.  If it is a new node, it's a root.
+  VMap::iterator SrcI= M.find(Src);
+  unsigned SrcID;
+
+  if (SrcI == M.end()) {
+    M[Src] = SrcID = Cntr++;
+    *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
+  }
+  else
+    SrcID = SrcI->second;
+
+  // Lookup the Dst.
+  VMap::iterator DstI= M.find(Dst);
+  unsigned DstID;
+
+  if (DstI == M.end()) {
+    M[Dst] = DstID = Cntr++;
+    *Out << "('vertex', " << DstID << ")\n";
+  }
+  else {
+    // We have hit DstID before.  Change its style to reflect a cache hit.
+    DstID = DstI->second;
+    *Out << "('change_vertex_style', " << DstID << ", 1)\n";
+  }
+
+  // Add the edge.
+  *Out << "('edge', " << SrcID << ", " << DstID
+       << ", ('arrow','true'), ('oriented', 'true'))\n";
+}
+
+UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
+                         llvm::sys::Path& filename)
+  : Out(out), Dir(dir), Filename(filename), Cntr(0) {
+
+  *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
+  *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
+          " ('size', '1.5'))\n";
+}
+
+UbigraphViz::~UbigraphViz() {
+  Out.reset(0);
+  llvm::errs() << "Running 'ubiviz' program... ";
+  std::string ErrMsg;
+  llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
+  std::vector<const char*> args;
+  args.push_back(Ubiviz.c_str());
+  args.push_back(Filename.c_str());
+  args.push_back(0);
+
+  if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
+    llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
+  }
+
+  // Delete the directory.
+  Dir.eraseFromDisk(true);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp
new file mode 100644 (file)
index 0000000..13e628b
--- /dev/null
@@ -0,0 +1,91 @@
+//== ArrayBoundChecker.cpp ------------------------------*- 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 ArrayBoundChecker, which is a path-sensitive check
+// which looks for an out-of-bound array element access.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ArrayBoundChecker : 
+    public CheckerVisitor<ArrayBoundChecker> {      
+  BuiltinBug *BT;
+public:
+  ArrayBoundChecker() : BT(0) {}
+  static void *getTag() { static int x = 0; return &x; }
+  void visitLocation(CheckerContext &C, const Stmt *S, SVal l);
+};
+}
+
+void ento::RegisterArrayBoundChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new ArrayBoundChecker());
+}
+
+void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l){
+  // Check for out of bound array element access.
+  const MemRegion *R = l.getAsRegion();
+  if (!R)
+    return;
+
+  const ElementRegion *ER = dyn_cast<ElementRegion>(R);
+  if (!ER)
+    return;
+
+  // Get the index of the accessed element.
+  DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+
+  // Zero index is always in bound, this also passes ElementRegions created for
+  // pointer casts.
+  if (Idx.isZeroConstant())
+    return;
+
+  const GRState *state = C.getState();
+
+  // Get the size of the array.
+  DefinedOrUnknownSVal NumElements 
+    = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 
+                                            ER->getValueType());
+
+  const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
+  const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
+  if (StOutBound && !StInBound) {
+    ExplodedNode *N = C.generateSink(StOutBound);
+    if (!N)
+      return;
+  
+    if (!BT)
+      BT = new BuiltinBug("Out-of-bound array access",
+                       "Access out-of-bound array element (buffer overflow)");
+
+    // FIXME: It would be nice to eventually make this diagnostic more clear,
+    // e.g., by referencing the original declaration or by saying *why* this
+    // reference is outside the range.
+
+    // Generate a report for this bug.
+    RangedBugReport *report = 
+      new RangedBugReport(*BT, BT->getDescription(), N);
+
+    report->addRange(S->getSourceRange());
+    C.EmitReport(report);
+    return;
+  }
+  
+  // Array bound check succeeded.  From this point forward the array bound
+  // should always succeed.
+  assert(StInBound);
+  C.addTransition(StInBound);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp
new file mode 100644 (file)
index 0000000..b55fade
--- /dev/null
@@ -0,0 +1,277 @@
+//== ArrayBoundCheckerV2.cpp ------------------------------------*- 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 ArrayBoundCheckerV2, which is a path-sensitive check
+// which looks for an out-of-bound array element access.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/AST/CharUnits.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ArrayBoundCheckerV2 : 
+    public CheckerVisitor<ArrayBoundCheckerV2> {      
+  BuiltinBug *BT;
+      
+  enum OOB_Kind { OOB_Precedes, OOB_Excedes };
+  
+  void reportOOB(CheckerContext &C, const GRState *errorState,
+                 OOB_Kind kind);
+      
+public:
+  ArrayBoundCheckerV2() : BT(0) {}
+  static void *getTag() { static int x = 0; return &x; }
+  void visitLocation(CheckerContext &C, const Stmt *S, SVal l);      
+};
+
+// FIXME: Eventually replace RegionRawOffset with this class.
+class RegionRawOffsetV2 {
+private:
+  const SubRegion *baseRegion;
+  SVal byteOffset;
+  
+  RegionRawOffsetV2()
+    : baseRegion(0), byteOffset(UnknownVal()) {}
+
+public:
+  RegionRawOffsetV2(const SubRegion* base, SVal offset)
+    : baseRegion(base), byteOffset(offset) {}
+
+  NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); }
+  const SubRegion *getRegion() const { return baseRegion; }
+  
+  static RegionRawOffsetV2 computeOffset(const GRState *state,
+                                         SValBuilder &svalBuilder,
+                                         SVal location);
+
+  void dump() const;
+  void dumpToStream(llvm::raw_ostream& os) const;
+};
+}
+
+void ento::RegisterArrayBoundCheckerV2(ExprEngine &Eng) {
+  Eng.registerCheck(new ArrayBoundCheckerV2());
+}
+
+void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext,
+                                        const Stmt *S,
+                                        SVal location) {
+
+  // NOTE: Instead of using GRState::assumeInBound(), we are prototyping
+  // some new logic here that reasons directly about memory region extents.
+  // Once that logic is more mature, we can bring it back to assumeInBound()
+  // for all clients to use.
+  //
+  // The algorithm we are using here for bounds checking is to see if the
+  // memory access is within the extent of the base region.  Since we
+  // have some flexibility in defining the base region, we can achieve
+  // various levels of conservatism in our buffer overflow checking.
+  const GRState *state = checkerContext.getState();  
+  const GRState *originalState = state;
+
+  SValBuilder &svalBuilder = checkerContext.getSValBuilder();
+  const RegionRawOffsetV2 &rawOffset = 
+    RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
+
+  if (!rawOffset.getRegion())
+    return;
+
+  // CHECK LOWER BOUND: Is byteOffset < 0?  If so, we are doing a load/store
+  //  before the first valid offset in the memory region.
+
+  SVal lowerBound
+    = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
+                              svalBuilder.makeZeroArrayIndex(),
+                              svalBuilder.getConditionType());
+
+  NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
+  if (!lowerBoundToCheck)
+    return;
+    
+  const GRState *state_precedesLowerBound, *state_withinLowerBound;
+  llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
+      state->assume(*lowerBoundToCheck);
+
+  // Are we constrained enough to definitely precede the lower bound?
+  if (state_precedesLowerBound && !state_withinLowerBound) {
+    reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
+    return;
+  }
+  
+  // Otherwise, assume the constraint of the lower bound.
+  assert(state_withinLowerBound);
+  state = state_withinLowerBound;
+  
+  do {
+    // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)?  If so,
+    // we are doing a load/store after the last valid offset.
+    DefinedOrUnknownSVal extentVal =
+      rawOffset.getRegion()->getExtent(svalBuilder);
+    if (!isa<NonLoc>(extentVal))
+      break;
+
+    SVal upperbound
+      = svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
+                                cast<NonLoc>(extentVal),
+                                svalBuilder.getConditionType());
+  
+    NonLoc *upperboundToCheck = dyn_cast<NonLoc>(&upperbound);
+    if (!upperboundToCheck)
+      break;
+  
+    const GRState *state_exceedsUpperBound, *state_withinUpperBound;
+    llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
+      state->assume(*upperboundToCheck);
+  
+    // Are we constrained enough to definitely exceed the upper bound?
+    if (state_exceedsUpperBound && !state_withinUpperBound) {
+      reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
+      return;
+    }
+  
+    assert(state_withinUpperBound);
+    state = state_withinUpperBound;
+  }
+  while (false);
+  
+  if (state != originalState)
+    checkerContext.generateNode(state);
+}
+
+void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
+                                    const GRState *errorState,
+                                    OOB_Kind kind) {
+  
+  ExplodedNode *errorNode = checkerContext.generateSink(errorState);
+  if (!errorNode)
+    return;
+
+  if (!BT)
+    BT = new BuiltinBug("Out-of-bound access");
+
+  // FIXME: This diagnostics are preliminary.  We should get far better
+  // diagnostics for explaining buffer overruns.
+
+  llvm::SmallString<256> buf;
+  llvm::raw_svector_ostream os(buf);
+  os << "Out of bound memory access "
+     << (kind == OOB_Precedes ? "(accessed memory precedes memory block)"
+                              : "(access exceeds upper limit of memory block)");
+
+  checkerContext.EmitReport(new RangedBugReport(*BT, os.str(), errorNode));
+}
+
+void RegionRawOffsetV2::dump() const {
+  dumpToStream(llvm::errs());
+}
+
+void RegionRawOffsetV2::dumpToStream(llvm::raw_ostream& os) const {
+  os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}';
+}
+
+// FIXME: Merge with the implementation of the same method in Store.cpp
+static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
+  if (const RecordType *RT = Ty->getAs<RecordType>()) {
+    const RecordDecl *D = RT->getDecl();
+    if (!D->getDefinition())
+      return false;
+  }
+
+  return true;
+}
+
+
+// Lazily computes a value to be used by 'computeOffset'.  If 'val'
+// is unknown or undefined, we lazily substitute '0'.  Otherwise,
+// return 'val'.
+static inline SVal getValue(SVal val, SValBuilder &svalBuilder) {
+  return isa<UndefinedVal>(val) ? svalBuilder.makeArrayIndex(0) : val;
+}
+
+// Scale a base value by a scaling factor, and return the scaled
+// value as an SVal.  Used by 'computeOffset'.
+static inline SVal scaleValue(const GRState *state,
+                              NonLoc baseVal, CharUnits scaling,
+                              SValBuilder &sb) {
+  return sb.evalBinOpNN(state, BO_Mul, baseVal,
+                        sb.makeArrayIndex(scaling.getQuantity()),
+                        sb.getArrayIndexType());
+}
+
+// Add an SVal to another, treating unknown and undefined values as
+// summing to UnknownVal.  Used by 'computeOffset'.
+static SVal addValue(const GRState *state, SVal x, SVal y,
+                     SValBuilder &svalBuilder) {
+  // We treat UnknownVals and UndefinedVals the same here because we
+  // only care about computing offsets.
+  if (x.isUnknownOrUndef() || y.isUnknownOrUndef())
+    return UnknownVal();
+  
+  return svalBuilder.evalBinOpNN(state, BO_Add,                                 
+                                 cast<NonLoc>(x), cast<NonLoc>(y),
+                                 svalBuilder.getArrayIndexType());
+}
+
+/// Compute a raw byte offset from a base region.  Used for array bounds
+/// checking.
+RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state,
+                                                   SValBuilder &svalBuilder,
+                                                   SVal location)
+{
+  const MemRegion *region = location.getAsRegion();
+  SVal offset = UndefinedVal();
+  
+  while (region) {
+    switch (region->getKind()) {
+      default: {
+        if (const SubRegion *subReg = dyn_cast<SubRegion>(region))
+          if (!offset.isUnknownOrUndef())
+            return RegionRawOffsetV2(subReg, offset);
+        return RegionRawOffsetV2();
+      }
+      case MemRegion::ElementRegionKind: {
+        const ElementRegion *elemReg = cast<ElementRegion>(region);
+        SVal index = elemReg->getIndex();
+        if (!isa<NonLoc>(index))
+          return RegionRawOffsetV2();
+        QualType elemType = elemReg->getElementType();
+        // If the element is an incomplete type, go no further.
+        ASTContext &astContext = svalBuilder.getContext();
+        if (!IsCompleteType(astContext, elemType))
+          return RegionRawOffsetV2();
+        
+        // Update the offset.
+        offset = addValue(state,
+                          getValue(offset, svalBuilder),
+                          scaleValue(state,
+                                     cast<NonLoc>(index),
+                                     astContext.getTypeSizeInChars(elemType),
+                                     svalBuilder),
+                          svalBuilder);
+
+        if (offset.isUnknownOrUndef())
+          return RegionRawOffsetV2();
+
+        region = elemReg->getSuperRegion();
+        continue;
+      }
+    }
+  }
+  return RegionRawOffsetV2();
+}
+
+
+
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp
new file mode 100644 (file)
index 0000000..646b30b
--- /dev/null
@@ -0,0 +1,136 @@
+//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines AttrNonNullChecker, a builtin check in ExprEngine that 
+// performs checks for arguments declared to have nonnull attribute.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class AttrNonNullChecker
+  : public CheckerVisitor<AttrNonNullChecker> {
+  BugType *BT;
+public:
+  AttrNonNullChecker() : BT(0) {}
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void ento::RegisterAttrNonNullChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new AttrNonNullChecker());
+}
+
+void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, 
+                                          const CallExpr *CE) {
+  const GRState *state = C.getState();
+
+  // Check if the callee has a 'nonnull' attribute.
+  SVal X = state->getSVal(CE->getCallee());
+
+  const FunctionDecl* FD = X.getAsFunctionDecl();
+  if (!FD)
+    return;
+
+  const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
+  if (!Att)
+    return;
+
+  // Iterate through the arguments of CE and check them for null.
+  unsigned idx = 0;
+
+  for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
+       ++I, ++idx) {
+
+    if (!Att->isNonNull(idx))
+      continue;
+
+    SVal V = state->getSVal(*I);
+    DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
+
+    // If the value is unknown or undefined, we can't perform this check.
+    if (!DV)
+      continue;
+
+    if (!isa<Loc>(*DV)) {
+      // If the argument is a union type, we want to handle a potential
+      // transparent_unoin GCC extension.
+      QualType T = (*I)->getType();
+      const RecordType *UT = T->getAsUnionType();
+      if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+        continue;
+      if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
+        nonloc::CompoundVal::iterator CSV_I = CSV->begin();
+        assert(CSV_I != CSV->end());
+        V = *CSV_I;
+        DV = dyn_cast<DefinedSVal>(&V);
+        assert(++CSV_I == CSV->end());
+        if (!DV)
+          continue;        
+      }
+      else {
+        // FIXME: Handle LazyCompoundVals?
+        continue;
+      }
+    }
+
+    ConstraintManager &CM = C.getConstraintManager();
+    const GRState *stateNotNull, *stateNull;
+    llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+
+    if (stateNull && !stateNotNull) {
+      // Generate an error node.  Check for a null node in case
+      // we cache out.
+      if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
+
+        // Lazily allocate the BugType object if it hasn't already been
+        // created. Ownership is transferred to the BugReporter object once
+        // the BugReport is passed to 'EmitWarning'.
+        if (!BT)
+          BT = new BugType("Argument with 'nonnull' attribute passed null",
+                           "API");
+
+        EnhancedBugReport *R =
+          new EnhancedBugReport(*BT,
+                                "Null pointer passed as an argument to a "
+                                "'nonnull' parameter", errorNode);
+
+        // Highlight the range of the argument that was null.
+        const Expr *arg = *I;
+        R->addRange(arg->getSourceRange());
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
+
+        // Emit the bug report.
+        C.EmitReport(R);
+      }
+
+      // Always return.  Either we cached out or we just emitted an error.
+      return;
+    }
+
+    // If a pointer value passed the check we should assume that it is
+    // indeed not null from this point forward.
+    assert(stateNotNull);
+    state = stateNotNull;
+  }
+
+  // If we reach here all of the arguments passed the nonnull check.
+  // If 'state' has been updated generated a new node.
+  C.addTransition(state);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp
new file mode 100644 (file)
index 0000000..b4e2959
--- /dev/null
@@ -0,0 +1,521 @@
+//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- 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 BasicObjCFoundationChecks, a class that encapsulates
+//  a set of simple checks to run on Objective-C code using Apple's Foundation
+//  classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BasicObjCFoundationChecks.h"
+
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class APIMisuse : public BugType {
+public:
+  APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
+  QualType T;
+  switch (ME->getReceiverKind()) {
+    case ObjCMessageExpr::Instance:
+      T = ME->getInstanceReceiver()->getType();
+      break;
+      
+    case ObjCMessageExpr::SuperInstance:
+      T = ME->getSuperType();
+      break;
+      
+    case ObjCMessageExpr::Class:
+    case ObjCMessageExpr::SuperClass:
+      return 0;
+  }
+  
+  if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
+    return PT->getInterfaceType();
+  
+  return NULL;
+}
+
+static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
+  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
+    return ReceiverType->getDecl()->getIdentifier()->getNameStart();
+  return NULL;
+}
+
+static bool isNSString(llvm::StringRef ClassName) {
+  return ClassName == "NSString" || ClassName == "NSMutableString";
+}
+
+static inline bool isNil(SVal X) {
+  return isa<loc::ConcreteInt>(X);
+}
+
+//===----------------------------------------------------------------------===//
+// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  class NilArgChecker : public CheckerVisitor<NilArgChecker> {
+    APIMisuse *BT;
+    void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
+  public:
+    NilArgChecker() : BT(0) {}
+    static void *getTag() { static int x = 0; return &x; }
+    void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+  };
+}
+
+void NilArgChecker::WarnNilArg(CheckerContext &C,
+                               const clang::ObjCMessageExpr *ME,
+                               unsigned int Arg)
+{
+  if (!BT)
+    BT = new APIMisuse("nil argument");
+  
+  if (ExplodedNode *N = C.generateSink()) {
+    llvm::SmallString<128> sbuf;
+    llvm::raw_svector_ostream os(sbuf);
+    os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
+       << ME->getSelector().getAsString() << "' cannot be nil";
+
+    RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
+    R->addRange(ME->getArg(Arg)->getSourceRange());
+    C.EmitReport(R);
+  }
+}
+
+void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+                                            const ObjCMessageExpr *ME)
+{
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
+  if (!ReceiverType)
+    return;
+  
+  if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
+    Selector S = ME->getSelector();
+    
+    if (S.isUnarySelector())
+      return;
+    
+    // FIXME: This is going to be really slow doing these checks with
+    //  lexical comparisons.
+    
+    std::string NameStr = S.getAsString();
+    llvm::StringRef Name(NameStr);
+    assert(!Name.empty());
+    
+    // FIXME: Checking for initWithFormat: will not work in most cases
+    //  yet because [NSString alloc] returns id, not NSString*.  We will
+    //  need support for tracking expected-type information in the analyzer
+    //  to find these errors.
+    if (Name == "caseInsensitiveCompare:" ||
+        Name == "compare:" ||
+        Name == "compare:options:" ||
+        Name == "compare:options:range:" ||
+        Name == "compare:options:range:locale:" ||
+        Name == "componentsSeparatedByCharactersInSet:" ||
+        Name == "initWithFormat:") {
+      if (isNil(C.getState()->getSVal(ME->getArg(0))))
+        WarnNilArg(C, ME, 0);
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Error reporting.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
+  APIMisuse* BT;
+  IdentifierInfo* II;
+public:
+  CFNumberCreateChecker() : BT(0), II(0) {}
+  ~CFNumberCreateChecker() {}
+  static void *getTag() { static int x = 0; return &x; }
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+private:
+  void EmitError(const TypedRegion* R, const Expr* Ex,
+                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
+};
+} // end anonymous namespace
+
+enum CFNumberType {
+  kCFNumberSInt8Type = 1,
+  kCFNumberSInt16Type = 2,
+  kCFNumberSInt32Type = 3,
+  kCFNumberSInt64Type = 4,
+  kCFNumberFloat32Type = 5,
+  kCFNumberFloat64Type = 6,
+  kCFNumberCharType = 7,
+  kCFNumberShortType = 8,
+  kCFNumberIntType = 9,
+  kCFNumberLongType = 10,
+  kCFNumberLongLongType = 11,
+  kCFNumberFloatType = 12,
+  kCFNumberDoubleType = 13,
+  kCFNumberCFIndexType = 14,
+  kCFNumberNSIntegerType = 15,
+  kCFNumberCGFloatType = 16
+};
+
+namespace {
+  template<typename T>
+  class Optional {
+    bool IsKnown;
+    T Val;
+  public:
+    Optional() : IsKnown(false), Val(0) {}
+    Optional(const T& val) : IsKnown(true), Val(val) {}
+
+    bool isKnown() const { return IsKnown; }
+
+    const T& getValue() const {
+      assert (isKnown());
+      return Val;
+    }
+
+    operator const T&() const {
+      return getValue();
+    }
+  };
+}
+
+static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
+  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
+
+  if (i < kCFNumberCharType)
+    return FixedSize[i-1];
+
+  QualType T;
+
+  switch (i) {
+    case kCFNumberCharType:     T = Ctx.CharTy;     break;
+    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
+    case kCFNumberIntType:      T = Ctx.IntTy;      break;
+    case kCFNumberLongType:     T = Ctx.LongTy;     break;
+    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
+    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
+    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
+    case kCFNumberCFIndexType:
+    case kCFNumberNSIntegerType:
+    case kCFNumberCGFloatType:
+      // FIXME: We need a way to map from names to Type*.
+    default:
+      return Optional<uint64_t>();
+  }
+
+  return Ctx.getTypeSize(T);
+}
+
+#if 0
+static const char* GetCFNumberTypeStr(uint64_t i) {
+  static const char* Names[] = {
+    "kCFNumberSInt8Type",
+    "kCFNumberSInt16Type",
+    "kCFNumberSInt32Type",
+    "kCFNumberSInt64Type",
+    "kCFNumberFloat32Type",
+    "kCFNumberFloat64Type",
+    "kCFNumberCharType",
+    "kCFNumberShortType",
+    "kCFNumberIntType",
+    "kCFNumberLongType",
+    "kCFNumberLongLongType",
+    "kCFNumberFloatType",
+    "kCFNumberDoubleType",
+    "kCFNumberCFIndexType",
+    "kCFNumberNSIntegerType",
+    "kCFNumberCGFloatType"
+  };
+
+  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
+}
+#endif
+
+void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
+                                             const CallExpr *CE)
+{
+  const Expr* Callee = CE->getCallee();
+  const GRState *state = C.getState();
+  SVal CallV = state->getSVal(Callee);
+  const FunctionDecl* FD = CallV.getAsFunctionDecl();
+
+  if (!FD)
+    return;
+  
+  ASTContext &Ctx = C.getASTContext();
+  if (!II)
+    II = &Ctx.Idents.get("CFNumberCreate");
+
+  if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
+    return;
+
+  // Get the value of the "theType" argument.
+  SVal TheTypeVal = state->getSVal(CE->getArg(1));
+
+  // FIXME: We really should allow ranges of valid theType values, and
+  //   bifurcate the state appropriately.
+  nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
+  if (!V)
+    return;
+
+  uint64_t NumberKind = V->getValue().getLimitedValue();
+  Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
+
+  // FIXME: In some cases we can emit an error.
+  if (!TargetSize.isKnown())
+    return;
+
+  // Look at the value of the integer being passed by reference.  Essentially
+  // we want to catch cases where the value passed in is not equal to the
+  // size of the type being created.
+  SVal TheValueExpr = state->getSVal(CE->getArg(2));
+
+  // FIXME: Eventually we should handle arbitrary locations.  We can do this
+  //  by having an enhanced memory model that does low-level typing.
+  loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
+  if (!LV)
+    return;
+
+  const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
+  if (!R)
+    return;
+
+  QualType T = Ctx.getCanonicalType(R->getValueType());
+
+  // FIXME: If the pointee isn't an integer type, should we flag a warning?
+  //  People can do weird stuff with pointers.
+
+  if (!T->isIntegerType())
+    return;
+
+  uint64_t SourceSize = Ctx.getTypeSize(T);
+
+  // CHECK: is SourceSize == TargetSize
+  if (SourceSize == TargetSize)
+    return;
+
+  // Generate an error.  Only generate a sink if 'SourceSize < TargetSize';
+  // otherwise generate a regular node.
+  //
+  // FIXME: We can actually create an abstract "CFNumber" object that has
+  //  the bits initialized to the provided values.
+  //
+  if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() 
+                                                : C.generateNode()) {
+    llvm::SmallString<128> sbuf;
+    llvm::raw_svector_ostream os(sbuf);
+    
+    os << (SourceSize == 8 ? "An " : "A ")
+       << SourceSize << " bit integer is used to initialize a CFNumber "
+                        "object that represents "
+       << (TargetSize == 8 ? "an " : "a ")
+       << TargetSize << " bit integer. ";
+    
+    if (SourceSize < TargetSize)
+      os << (TargetSize - SourceSize)
+      << " bits of the CFNumber value will be garbage." ;
+    else
+      os << (SourceSize - TargetSize)
+      << " bits of the input integer will be lost.";
+
+    if (!BT)
+      BT = new APIMisuse("Bad use of CFNumberCreate");
+    
+    RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+    report->addRange(CE->getArg(2)->getSourceRange());
+    C.EmitReport(report);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// CFRetain/CFRelease checking for null arguments.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
+  APIMisuse *BT;
+  IdentifierInfo *Retain, *Release;
+public:
+  CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
+  static void *getTag() { static int x = 0; return &x; }
+  void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
+};
+} // end anonymous namespace
+
+
+void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
+                                              const CallExpr* CE) {
+  // If the CallExpr doesn't have exactly 1 argument just give up checking.
+  if (CE->getNumArgs() != 1)
+    return;
+
+  // Get the function declaration of the callee.
+  const GRState* state = C.getState();
+  SVal X = state->getSVal(CE->getCallee());
+  const FunctionDecl* FD = X.getAsFunctionDecl();
+
+  if (!FD)
+    return;
+  
+  if (!BT) {
+    ASTContext &Ctx = C.getASTContext();
+    Retain = &Ctx.Idents.get("CFRetain");
+    Release = &Ctx.Idents.get("CFRelease");
+    BT = new APIMisuse("null passed to CFRetain/CFRelease");
+  }
+
+  // Check if we called CFRetain/CFRelease.
+  const IdentifierInfo *FuncII = FD->getIdentifier();
+  if (!(FuncII == Retain || FuncII == Release))
+    return;
+
+  // FIXME: The rest of this just checks that the argument is non-null.
+  // It should probably be refactored and combined with AttrNonNullChecker.
+
+  // Get the argument's value.
+  const Expr *Arg = CE->getArg(0);
+  SVal ArgVal = state->getSVal(Arg);
+  DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
+  if (!DefArgVal)
+    return;
+
+  // Get a NULL value.
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
+
+  // Make an expression asserting that they're equal.
+  DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
+
+  // Are they equal?
+  const GRState *stateTrue, *stateFalse;
+  llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
+
+  if (stateTrue && !stateFalse) {
+    ExplodedNode *N = C.generateSink(stateTrue);
+    if (!N)
+      return;
+
+    const char *description = (FuncII == Retain)
+                            ? "Null pointer argument in call to CFRetain"
+                            : "Null pointer argument in call to CFRelease";
+
+    EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
+    report->addRange(Arg->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
+    C.EmitReport(report);
+    return;
+  }
+
+  // From here on, we know the argument is non-null.
+  C.addTransition(stateFalse);
+}
+
+//===----------------------------------------------------------------------===//
+// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
+  Selector releaseS;
+  Selector retainS;
+  Selector autoreleaseS;
+  Selector drainS;
+  BugType *BT;
+public:
+  ClassReleaseChecker()
+    : BT(0) {}
+
+  static void *getTag() { static int x = 0; return &x; }
+      
+  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);    
+};
+}
+
+void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+                                                  const ObjCMessageExpr *ME) {
+  
+  if (!BT) {
+    BT = new APIMisuse("message incorrectly sent to class instead of class "
+                       "instance");
+  
+    ASTContext &Ctx = C.getASTContext();
+    releaseS = GetNullarySelector("release", Ctx);
+    retainS = GetNullarySelector("retain", Ctx);
+    autoreleaseS = GetNullarySelector("autorelease", Ctx);
+    drainS = GetNullarySelector("drain", Ctx);
+  }
+  
+  ObjCInterfaceDecl *Class = 0;
+
+  switch (ME->getReceiverKind()) {
+  case ObjCMessageExpr::Class:
+    Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
+    break;
+  case ObjCMessageExpr::SuperClass:
+    Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
+    break;
+  case ObjCMessageExpr::Instance:
+  case ObjCMessageExpr::SuperInstance:
+    return;
+  }
+
+  Selector S = ME->getSelector();
+  if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
+    return;
+  
+  if (ExplodedNode *N = C.generateNode()) {
+    llvm::SmallString<200> buf;
+    llvm::raw_svector_ostream os(buf);
+
+    os << "The '" << S.getAsString() << "' message should be sent to instances "
+          "of class '" << Class->getName()
+       << "' and not the class directly";
+  
+    RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+    report->addRange(ME->getSourceRange());
+    C.EmitReport(report);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Check registration.
+//===----------------------------------------------------------------------===//
+  
+void ento::RegisterAppleChecks(ExprEngine& Eng, const Decl &D) {
+  Eng.registerCheck(new NilArgChecker());
+  Eng.registerCheck(new CFNumberCreateChecker());
+  RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D);
+  RegisterNSAutoreleasePoolChecks(Eng);
+  Eng.registerCheck(new CFRetainReleaseChecker());
+  Eng.registerCheck(new ClassReleaseChecker());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h b/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h
new file mode 100644 (file)
index 0000000..f4966e8
--- /dev/null
@@ -0,0 +1,36 @@
+//== BasicObjCFoundationChecks.h - Simple Apple-Foundation checks -*- 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 BasicObjCFoundationChecks, a class that encapsulates
+//  a set of simple checks to run on Objective-C code using Apple's Foundation
+//  classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS
+#define LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS
+
+namespace clang {
+
+class ASTContext;
+class Decl;
+
+namespace ento {
+
+class BugReporter;
+class ExprEngine;
+
+void RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, const Decl &D);
+void RegisterNSAutoreleasePoolChecks(ExprEngine &Eng);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp
new file mode 100644 (file)
index 0000000..2e6f1b9
--- /dev/null
@@ -0,0 +1,83 @@
+//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker evaluates clang builtin functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+#include "clang/Basic/Builtins.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class BuiltinFunctionChecker : public Checker {
+public:
+  static void *getTag() { static int tag = 0; return &tag; }
+  virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void ento::RegisterBuiltinFunctionChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new BuiltinFunctionChecker());
+}
+
+bool BuiltinFunctionChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE){
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+  const FunctionDecl *FD = L.getAsFunctionDecl();
+
+  if (!FD)
+    return false;
+
+  unsigned id = FD->getBuiltinID();
+
+  if (!id)
+    return false;
+
+  switch (id) {
+  case Builtin::BI__builtin_expect: {
+    // For __builtin_expect, just return the value of the subexpression.
+    assert (CE->arg_begin() != CE->arg_end());
+    SVal X = state->getSVal(*(CE->arg_begin()));
+    C.generateNode(state->BindExpr(CE, X));
+    return true;
+  }
+
+  case Builtin::BI__builtin_alloca: {
+    // FIXME: Refactor into StoreManager itself?
+    MemRegionManager& RM = C.getStoreManager().getRegionManager();
+    const AllocaRegion* R =
+      RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(),
+                         C.getPredecessor()->getLocationContext());
+
+    // Set the extent of the region in bytes. This enables us to use the
+    // SVal of the argument directly. If we save the extent in bits, we
+    // cannot represent values like symbol*8.
+    DefinedOrUnknownSVal Size =
+      cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin())));
+
+    SValBuilder& svalBuilder = C.getSValBuilder();
+    DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
+    DefinedOrUnknownSVal extentMatchesSizeArg =
+      svalBuilder.evalEQ(state, Extent, Size);
+    state = state->assume(extentMatchesSizeArg, true);
+
+    C.generateNode(state->BindExpr(CE, loc::MemRegionVal(R)));
+    return true;
+  }
+  }
+
+  return false;
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4b9541
--- /dev/null
@@ -0,0 +1,53 @@
+add_clang_library(clangStaticAnalyzerCheckers
+  AdjustedReturnValueChecker.cpp
+  AnalysisConsumer.cpp
+  ArrayBoundChecker.cpp
+  ArrayBoundCheckerV2.cpp
+  AttrNonNullChecker.cpp
+  BasicObjCFoundationChecks.cpp
+  BuiltinFunctionChecker.cpp
+  CStringChecker.cpp
+  CallAndMessageChecker.cpp
+  CastSizeChecker.cpp
+  CastToStructChecker.cpp
+  CheckDeadStores.cpp
+  CheckObjCDealloc.cpp
+  CheckObjCInstMethSignature.cpp
+  CheckSecuritySyntaxOnly.cpp
+  CheckSizeofPointer.cpp
+  ChrootChecker.cpp
+  DereferenceChecker.cpp
+  DivZeroChecker.cpp
+  ExprEngine.cpp
+  ExprEngineExperimentalChecks.cpp
+  FixedAddressChecker.cpp
+  FrontendActions.cpp
+  IdempotentOperationChecker.cpp
+  LLVMConventionsChecker.cpp
+  MacOSXAPIChecker.cpp
+  MallocChecker.cpp
+  NSAutoreleasePoolChecker.cpp
+  NSErrorChecker.cpp
+  NoReturnFunctionChecker.cpp
+  OSAtomicChecker.cpp
+  ObjCAtSyncChecker.cpp
+  ObjCUnusedIVarsChecker.cpp
+  PointerArithChecker.cpp
+  PointerSubChecker.cpp
+  PthreadLockChecker.cpp
+  ReturnPointerRangeChecker.cpp
+  ReturnUndefChecker.cpp
+  StackAddrLeakChecker.cpp
+  StreamChecker.cpp
+  UndefBranchChecker.cpp
+  UndefCapturedBlockVarChecker.cpp
+  UndefResultChecker.cpp
+  UndefinedArraySubscriptChecker.cpp
+  UndefinedAssignmentChecker.cpp
+  UnixAPIChecker.cpp
+  UnreachableCodeChecker.cpp
+  VLASizeChecker.cpp
+  )
+
+add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
+                 ClangStmtNodes)
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp
new file mode 100644 (file)
index 0000000..b7513c3
--- /dev/null
@@ -0,0 +1,1048 @@
+//= CStringChecker.h - Checks calls to C string functions ----------*- C++ -*-//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines CStringChecker, which is an assortment of checks on calls
+// to functions in <string.h>.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineExperimentalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class CStringChecker : public CheckerVisitor<CStringChecker> {
+  BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString;
+public:
+  CStringChecker()
+  : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0)
+  {}
+  static void *getTag() { static int tag; return &tag; }
+
+  bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+  void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
+  void MarkLiveSymbols(const GRState *state, SymbolReaper &SR);
+  void evalDeadSymbols(CheckerContext &C, SymbolReaper &SR);
+  bool WantsRegionChangeUpdate(const GRState *state);
+
+  const GRState *EvalRegionChanges(const GRState *state,
+                                   const MemRegion * const *Begin,
+                                   const MemRegion * const *End,
+                                   bool*);
+
+  typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *);
+
+  void evalMemcpy(CheckerContext &C, const CallExpr *CE);
+  void evalMemmove(CheckerContext &C, const CallExpr *CE);
+  void evalBcopy(CheckerContext &C, const CallExpr *CE);
+  void evalCopyCommon(CheckerContext &C, const GRState *state,
+                      const Expr *Size, const Expr *Source, const Expr *Dest,
+                      bool Restricted = false);
+
+  void evalMemcmp(CheckerContext &C, const CallExpr *CE);
+
+  void evalstrLength(CheckerContext &C, const CallExpr *CE);
+
+  void evalStrcpy(CheckerContext &C, const CallExpr *CE);
+  void evalStpcpy(CheckerContext &C, const CallExpr *CE);
+  void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd);
+
+  // Utility methods
+  std::pair<const GRState*, const GRState*>
+  assumeZero(CheckerContext &C, const GRState *state, SVal V, QualType Ty);
+
+  const GRState *setCStringLength(const GRState *state, const MemRegion *MR,
+                                  SVal strLength);
+  SVal getCStringLengthForRegion(CheckerContext &C, const GRState *&state,
+                                 const Expr *Ex, const MemRegion *MR);
+  SVal getCStringLength(CheckerContext &C, const GRState *&state,
+                        const Expr *Ex, SVal Buf);
+
+  const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state,
+                                  const Expr *Ex, SVal V);
+
+  bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+                       const MemRegion *MR);
+
+  // Re-usable checks
+  const GRState *checkNonNull(CheckerContext &C, const GRState *state,
+                               const Expr *S, SVal l);
+  const GRState *CheckLocation(CheckerContext &C, const GRState *state,
+                               const Expr *S, SVal l,
+                               bool IsDestination = false);
+  const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
+                                   const Expr *Size,
+                                   const Expr *FirstBuf,
+                                   const Expr *SecondBuf = NULL,
+                                   bool FirstIsDestination = false);
+  const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
+                              const Expr *Size, const Expr *First,
+                              const Expr *Second);
+  void emitOverlapBug(CheckerContext &C, const GRState *state,
+                      const Stmt *First, const Stmt *Second);
+};
+
+class CStringLength {
+public:
+  typedef llvm::ImmutableMap<const MemRegion *, SVal> EntryMap;
+};
+} //end anonymous namespace
+
+namespace clang {
+namespace ento {
+  template <>
+  struct GRStateTrait<CStringLength> 
+    : public GRStatePartialTrait<CStringLength::EntryMap> {
+    static void *GDMIndex() { return CStringChecker::getTag(); }
+  };
+}
+}
+
+void ento::RegisterCStringChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new CStringChecker());
+}
+
+//===----------------------------------------------------------------------===//
+// Individual checks and utility methods.
+//===----------------------------------------------------------------------===//
+
+std::pair<const GRState*, const GRState*>
+CStringChecker::assumeZero(CheckerContext &C, const GRState *state, SVal V,
+                           QualType Ty) {
+  DefinedSVal *val = dyn_cast<DefinedSVal>(&V);
+  if (!val)
+    return std::pair<const GRState*, const GRState *>(state, state);
+
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
+  return state->assume(svalBuilder.evalEQ(state, *val, zero));
+}
+
+const GRState *CStringChecker::checkNonNull(CheckerContext &C,
+                                            const GRState *state,
+                                            const Expr *S, SVal l) {
+  // If a previous check has failed, propagate the failure.
+  if (!state)
+    return NULL;
+
+  const GRState *stateNull, *stateNonNull;
+  llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType());
+
+  if (stateNull && !stateNonNull) {
+    ExplodedNode *N = C.generateSink(stateNull);
+    if (!N)
+      return NULL;
+
+    if (!BT_Null)
+      BT_Null = new BuiltinBug("API",
+        "Null pointer argument in call to byte string function");
+
+    // Generate a report for this bug.
+    BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null);
+    EnhancedBugReport *report = new EnhancedBugReport(*BT,
+                                                      BT->getDescription(), N);
+
+    report->addRange(S->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, S);
+    C.EmitReport(report);
+    return NULL;
+  }
+
+  // From here on, assume that the value is non-null.
+  assert(stateNonNull);
+  return stateNonNull;
+}
+
+// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
+const GRState *CStringChecker::CheckLocation(CheckerContext &C,
+                                             const GRState *state,
+                                             const Expr *S, SVal l,
+                                             bool IsDestination) {
+  // If a previous check has failed, propagate the failure.
+  if (!state)
+    return NULL;
+
+  // Check for out of bound array element access.
+  const MemRegion *R = l.getAsRegion();
+  if (!R)
+    return state;
+
+  const ElementRegion *ER = dyn_cast<ElementRegion>(R);
+  if (!ER)
+    return state;
+
+  assert(ER->getValueType() == C.getASTContext().CharTy &&
+    "CheckLocation should only be called with char* ElementRegions");
+
+  // Get the size of the array.
+  const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  SVal Extent = svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
+  DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Extent);
+
+  // Get the index of the accessed element.
+  DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+
+  const GRState *StInBound = state->assumeInBound(Idx, Size, true);
+  const GRState *StOutBound = state->assumeInBound(Idx, Size, false);
+  if (StOutBound && !StInBound) {
+    ExplodedNode *N = C.generateSink(StOutBound);
+    if (!N)
+      return NULL;
+
+    BuiltinBug *BT;
+    if (IsDestination) {
+      if (!BT_BoundsWrite) {
+        BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
+          "Byte string function overflows destination buffer");
+      }
+      BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
+    } else {
+      if (!BT_Bounds) {
+        BT_Bounds = new BuiltinBug("Out-of-bound array access",
+          "Byte string function accesses out-of-bound array element");
+      }
+      BT = static_cast<BuiltinBug*>(BT_Bounds);
+    }
+
+    // FIXME: It would be nice to eventually make this diagnostic more clear,
+    // e.g., by referencing the original declaration or by saying *why* this
+    // reference is outside the range.
+
+    // Generate a report for this bug.
+    RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N);
+
+    report->addRange(S->getSourceRange());
+    C.EmitReport(report);
+    return NULL;
+  }
+  
+  // Array bound check succeeded.  From this point forward the array bound
+  // should always succeed.
+  return StInBound;
+}
+
+const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
+                                                 const GRState *state,
+                                                 const Expr *Size,
+                                                 const Expr *FirstBuf,
+                                                 const Expr *SecondBuf,
+                                                 bool FirstIsDestination) {
+  // If a previous check has failed, propagate the failure.
+  if (!state)
+    return NULL;
+
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  ASTContext &Ctx = C.getASTContext();
+
+  QualType sizeTy = Size->getType();
+  QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
+
+  // Check that the first buffer is non-null.
+  SVal BufVal = state->getSVal(FirstBuf);
+  state = checkNonNull(C, state, FirstBuf, BufVal);
+  if (!state)
+    return NULL;
+
+  // Get the access length and make sure it is known.
+  SVal LengthVal = state->getSVal(Size);
+  NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
+  if (!Length)
+    return state;
+
+  // Compute the offset of the last element to be accessed: size-1.
+  NonLoc One = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
+  NonLoc LastOffset = cast<NonLoc>(svalBuilder.evalBinOpNN(state, BO_Sub,
+                                                    *Length, One, sizeTy));
+
+  // Check that the first buffer is sufficently long.
+  SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
+  if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+    SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
+                                          LastOffset, PtrTy);
+    state = CheckLocation(C, state, FirstBuf, BufEnd, FirstIsDestination);
+
+    // If the buffer isn't large enough, abort.
+    if (!state)
+      return NULL;
+  }
+
+  // If there's a second buffer, check it as well.
+  if (SecondBuf) {
+    BufVal = state->getSVal(SecondBuf);
+    state = checkNonNull(C, state, SecondBuf, BufVal);
+    if (!state)
+      return NULL;
+
+    BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType());
+    if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+      SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
+                                            LastOffset, PtrTy);
+      state = CheckLocation(C, state, SecondBuf, BufEnd);
+    }
+  }
+
+  // Large enough or not, return this state!
+  return state;
+}
+
+const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
+                                            const GRState *state,
+                                            const Expr *Size,
+                                            const Expr *First,
+                                            const Expr *Second) {
+  // Do a simple check for overlap: if the two arguments are from the same
+  // buffer, see if the end of the first is greater than the start of the second
+  // or vice versa.
+
+  // If a previous check has failed, propagate the failure.
+  if (!state)
+    return NULL;
+
+  const GRState *stateTrue, *stateFalse;
+
+  // Get the buffer values and make sure they're known locations.
+  SVal firstVal = state->getSVal(First);
+  SVal secondVal = state->getSVal(Second);
+
+  Loc *firstLoc = dyn_cast<Loc>(&firstVal);
+  if (!firstLoc)
+    return state;
+
+  Loc *secondLoc = dyn_cast<Loc>(&secondVal);
+  if (!secondLoc)
+    return state;
+
+  // Are the two values the same?
+  SValBuilder &svalBuilder = C.getSValBuilder();  
+  llvm::tie(stateTrue, stateFalse) =
+    state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
+
+  if (stateTrue && !stateFalse) {
+    // If the values are known to be equal, that's automatically an overlap.
+    emitOverlapBug(C, stateTrue, First, Second);
+    return NULL;
+  }
+
+  // assume the two expressions are not equal.
+  assert(stateFalse);
+  state = stateFalse;
+
+  // Which value comes first?
+  ASTContext &Ctx = svalBuilder.getContext();
+  QualType cmpTy = Ctx.IntTy;
+  SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT,
+                                         *firstLoc, *secondLoc, cmpTy);
+  DefinedOrUnknownSVal *reverseTest = dyn_cast<DefinedOrUnknownSVal>(&reverse);
+  if (!reverseTest)
+    return state;
+
+  llvm::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
+  if (stateTrue) {
+    if (stateFalse) {
+      // If we don't know which one comes first, we can't perform this test.
+      return state;
+    } else {
+      // Switch the values so that firstVal is before secondVal.
+      Loc *tmpLoc = firstLoc;
+      firstLoc = secondLoc;
+      secondLoc = tmpLoc;
+
+      // Switch the Exprs as well, so that they still correspond.
+      const Expr *tmpExpr = First;
+      First = Second;
+      Second = tmpExpr;
+    }
+  }
+
+  // Get the length, and make sure it too is known.
+  SVal LengthVal = state->getSVal(Size);
+  NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
+  if (!Length)
+    return state;
+
+  // Convert the first buffer's start address to char*.
+  // Bail out if the cast fails.
+  QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+  SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, First->getType());
+  Loc *FirstStartLoc = dyn_cast<Loc>(&FirstStart);
+  if (!FirstStartLoc)
+    return state;
+
+  // Compute the end of the first buffer. Bail out if THAT fails.
+  SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add,
+                                 *FirstStartLoc, *Length, CharPtrTy);
+  Loc *FirstEndLoc = dyn_cast<Loc>(&FirstEnd);
+  if (!FirstEndLoc)
+    return state;
+
+  // Is the end of the first buffer past the start of the second buffer?
+  SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT,
+                                *FirstEndLoc, *secondLoc, cmpTy);
+  DefinedOrUnknownSVal *OverlapTest = dyn_cast<DefinedOrUnknownSVal>(&Overlap);
+  if (!OverlapTest)
+    return state;
+
+  llvm::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
+
+  if (stateTrue && !stateFalse) {
+    // Overlap!
+    emitOverlapBug(C, stateTrue, First, Second);
+    return NULL;
+  }
+
+  // assume the two expressions don't overlap.
+  assert(stateFalse);
+  return stateFalse;
+}
+
+void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
+                                    const Stmt *First, const Stmt *Second) {
+  ExplodedNode *N = C.generateSink(state);
+  if (!N)
+    return;
+
+  if (!BT_Overlap)
+    BT_Overlap = new BugType("Unix API", "Improper arguments");
+
+  // Generate a report for this bug.
+  RangedBugReport *report = 
+    new RangedBugReport(*BT_Overlap,
+      "Arguments must not be overlapping buffers", N);
+  report->addRange(First->getSourceRange());
+  report->addRange(Second->getSourceRange());
+
+  C.EmitReport(report);
+}
+
+const GRState *CStringChecker::setCStringLength(const GRState *state,
+                                                const MemRegion *MR,
+                                                SVal strLength) {
+  assert(!strLength.isUndef() && "Attempt to set an undefined string length");
+  if (strLength.isUnknown())
+    return state;
+
+  MR = MR->StripCasts();
+
+  switch (MR->getKind()) {
+  case MemRegion::StringRegionKind:
+    // FIXME: This can happen if we strcpy() into a string region. This is
+    // undefined [C99 6.4.5p6], but we should still warn about it.
+    return state;
+
+  case MemRegion::SymbolicRegionKind:
+  case MemRegion::AllocaRegionKind:
+  case MemRegion::VarRegionKind:
+  case MemRegion::FieldRegionKind:
+  case MemRegion::ObjCIvarRegionKind:
+    return state->set<CStringLength>(MR, strLength);
+
+  case MemRegion::ElementRegionKind:
+    // FIXME: Handle element regions by upper-bounding the parent region's
+    // string length.
+    return state;
+
+  default:
+    // Other regions (mostly non-data) can't have a reliable C string length.
+    // For now, just ignore the change.
+    // FIXME: These are rare but not impossible. We should output some kind of
+    // warning for things like strcpy((char[]){'a', 0}, "b");
+    return state;
+  }
+}
+
+SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
+                                               const GRState *&state,
+                                               const Expr *Ex,
+                                               const MemRegion *MR) {
+  // If there's a recorded length, go ahead and return it.
+  const SVal *Recorded = state->get<CStringLength>(MR);
+  if (Recorded)
+    return *Recorded;
+  
+  // Otherwise, get a new symbol and update the state.
+  unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  QualType sizeTy = svalBuilder.getContext().getSizeType();
+  SVal strLength = svalBuilder.getMetadataSymbolVal(getTag(), MR, Ex, sizeTy, Count);
+  state = state->set<CStringLength>(MR, strLength);
+  return strLength;
+}
+
+SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
+                                      const Expr *Ex, SVal Buf) {
+  const MemRegion *MR = Buf.getAsRegion();
+  if (!MR) {
+    // If we can't get a region, see if it's something we /know/ isn't a
+    // C string. In the context of locations, the only time we can issue such
+    // a warning is for labels.
+    if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
+      if (ExplodedNode *N = C.generateNode(state)) {
+        if (!BT_NotCString)
+          BT_NotCString = new BuiltinBug("API",
+            "Argument is not a null-terminated string.");
+
+        llvm::SmallString<120> buf;
+        llvm::raw_svector_ostream os(buf);
+        os << "Argument to byte string function is the address of the label '"
+           << Label->getLabel()->getID()->getName()
+           << "', which is not a null-terminated string";
+
+        // Generate a report for this bug.
+        EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString,
+                                                          os.str(), N);
+
+        report->addRange(Ex->getSourceRange());
+        C.EmitReport(report);        
+      }
+
+      return UndefinedVal();
+    }
+
+    // If it's not a region and not a label, give up.
+    return UnknownVal();
+  }
+
+  // If we have a region, strip casts from it and see if we can figure out
+  // its length. For anything we can't figure out, just return UnknownVal.
+  MR = MR->StripCasts();
+
+  switch (MR->getKind()) {
+  case MemRegion::StringRegionKind: {
+    // Modifying the contents of string regions is undefined [C99 6.4.5p6],
+    // so we can assume that the byte length is the correct C string length.
+    SValBuilder &svalBuilder = C.getSValBuilder();
+    QualType sizeTy = svalBuilder.getContext().getSizeType();
+    const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
+    return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy);
+  }
+  case MemRegion::SymbolicRegionKind:
+  case MemRegion::AllocaRegionKind:
+  case MemRegion::VarRegionKind:
+  case MemRegion::FieldRegionKind:
+  case MemRegion::ObjCIvarRegionKind:
+    return getCStringLengthForRegion(C, state, Ex, MR);
+  case MemRegion::CompoundLiteralRegionKind:
+    // FIXME: Can we track this? Is it necessary?
+    return UnknownVal();
+  case MemRegion::ElementRegionKind:
+    // FIXME: How can we handle this? It's not good enough to subtract the
+    // offset from the base string length; consider "123\x00567" and &a[5].
+    return UnknownVal();
+  default:
+    // Other regions (mostly non-data) can't have a reliable C string length.
+    // In this case, an error is emitted and UndefinedVal is returned.
+    // The caller should always be prepared to handle this case.
+    if (ExplodedNode *N = C.generateNode(state)) {
+      if (!BT_NotCString)
+        BT_NotCString = new BuiltinBug("API",
+          "Argument is not a null-terminated string.");
+
+      llvm::SmallString<120> buf;
+      llvm::raw_svector_ostream os(buf);
+
+      os << "Argument to byte string function is ";
+
+      if (SummarizeRegion(os, C.getASTContext(), MR))
+        os << ", which is not a null-terminated string";
+      else
+        os << "not a null-terminated string";
+
+      // Generate a report for this bug.
+      EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString,
+                                                        os.str(), N);
+
+      report->addRange(Ex->getSourceRange());
+      C.EmitReport(report);        
+    }
+
+    return UndefinedVal();
+  }
+}
+
+const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
+                                                const GRState *state,
+                                                const Expr *E, SVal V) {
+  Loc *L = dyn_cast<Loc>(&V);
+  if (!L)
+    return state;
+
+  // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
+  // some assumptions about the value that CFRefCount can't. Even so, it should
+  // probably be refactored.
+  if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(L)) {
+    const MemRegion *R = MR->getRegion()->StripCasts();
+
+    // Are we dealing with an ElementRegion?  If so, we should be invalidating
+    // the super-region.
+    if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+      R = ER->getSuperRegion();
+      // FIXME: What about layers of ElementRegions?
+    }
+
+    // Invalidate this region.
+    unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+    return state->InvalidateRegion(R, E, Count, NULL);
+  }
+
+  // If we have a non-region value by chance, just remove the binding.
+  // FIXME: is this necessary or correct? This handles the non-Region
+  //  cases.  Is it ever valid to store to these?
+  return state->unbindLoc(*L);
+}
+
+bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
+                                     const MemRegion *MR) {
+  const TypedRegion *TR = dyn_cast<TypedRegion>(MR);
+  if (!TR)
+    return false;
+
+  switch (TR->getKind()) {
+  case MemRegion::FunctionTextRegionKind: {
+    const FunctionDecl *FD = cast<FunctionTextRegion>(TR)->getDecl();
+    if (FD)
+      os << "the address of the function '" << FD << "'";
+    else
+      os << "the address of a function";
+    return true;
+  }
+  case MemRegion::BlockTextRegionKind:
+    os << "block text";
+    return true;
+  case MemRegion::BlockDataRegionKind:
+    os << "a block";
+    return true;
+  case MemRegion::CXXThisRegionKind:
+  case MemRegion::CXXTempObjectRegionKind:
+    os << "a C++ temp object of type " << TR->getValueType().getAsString();
+    return true;
+  case MemRegion::VarRegionKind:
+    os << "a variable of type" << TR->getValueType().getAsString();
+    return true;
+  case MemRegion::FieldRegionKind:
+    os << "a field of type " << TR->getValueType().getAsString();
+    return true;
+  case MemRegion::ObjCIvarRegionKind:
+    os << "an instance variable of type " << TR->getValueType().getAsString();
+    return true;
+  default:
+    return false;
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// evaluation of individual function calls.
+//===----------------------------------------------------------------------===//
+
+void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
+                                    const Expr *Size, const Expr *Dest,
+                                    const Expr *Source, bool Restricted) {
+  // See if the size argument is zero.
+  SVal sizeVal = state->getSVal(Size);
+  QualType sizeTy = Size->getType();
+
+  const GRState *stateZeroSize, *stateNonZeroSize;
+  llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy);
+
+  // If the size is zero, there won't be any actual memory access.
+  if (stateZeroSize)
+    C.addTransition(stateZeroSize);
+
+  // If the size can be nonzero, we have to check the other arguments.
+  if (stateNonZeroSize) {
+    state = stateNonZeroSize;
+    state = CheckBufferAccess(C, state, Size, Dest, Source,
+                              /* FirstIsDst = */ true);
+    if (Restricted)
+      state = CheckOverlap(C, state, Size, Dest, Source);
+
+    if (state) {
+      // Invalidate the destination.
+      // FIXME: Even if we can't perfectly model the copy, we should see if we
+      // can use LazyCompoundVals to copy the source values into the destination.
+      // This would probably remove any existing bindings past the end of the
+      // copied region, but that's still an improvement over blank invalidation.
+      state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
+      C.addTransition(state);
+    }
+  }
+}
+
+
+void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
+  // void *memcpy(void *restrict dst, const void *restrict src, size_t n);
+  // The return value is the address of the destination buffer.
+  const Expr *Dest = CE->getArg(0);
+  const GRState *state = C.getState();
+  state = state->BindExpr(CE, state->getSVal(Dest));
+  evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
+}
+
+void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
+  // void *memmove(void *dst, const void *src, size_t n);
+  // The return value is the address of the destination buffer.
+  const Expr *Dest = CE->getArg(0);
+  const GRState *state = C.getState();
+  state = state->BindExpr(CE, state->getSVal(Dest));
+  evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
+}
+
+void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) {
+  // void bcopy(const void *src, void *dst, size_t n);
+  evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
+}
+
+void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
+  // int memcmp(const void *s1, const void *s2, size_t n);
+  const Expr *Left = CE->getArg(0);
+  const Expr *Right = CE->getArg(1);
+  const Expr *Size = CE->getArg(2);
+
+  const GRState *state = C.getState();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+
+  // See if the size argument is zero.
+  SVal sizeVal = state->getSVal(Size);
+  QualType sizeTy = Size->getType();
+
+  const GRState *stateZeroSize, *stateNonZeroSize;
+  llvm::tie(stateZeroSize, stateNonZeroSize) =
+    assumeZero(C, state, sizeVal, sizeTy);
+
+  // If the size can be zero, the result will be 0 in that case, and we don't
+  // have to check either of the buffers.
+  if (stateZeroSize) {
+    state = stateZeroSize;
+    state = state->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+    C.addTransition(state);
+  }
+
+  // If the size can be nonzero, we have to check the other arguments.
+  if (stateNonZeroSize) {
+    state = stateNonZeroSize;
+    // If we know the two buffers are the same, we know the result is 0.
+    // First, get the two buffers' addresses. Another checker will have already
+    // made sure they're not undefined.
+    DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(state->getSVal(Left));
+    DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(state->getSVal(Right));
+
+    // See if they are the same.
+    DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
+    const GRState *StSameBuf, *StNotSameBuf;
+    llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
+
+    // If the two arguments might be the same buffer, we know the result is zero,
+    // and we only need to check one size.
+    if (StSameBuf) {
+      state = StSameBuf;
+      state = CheckBufferAccess(C, state, Size, Left);
+      if (state) {
+        state = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
+        C.addTransition(state); 
+      }
+    }
+
+    // If the two arguments might be different buffers, we have to check the
+    // size of both of them.
+    if (StNotSameBuf) {
+      state = StNotSameBuf;
+      state = CheckBufferAccess(C, state, Size, Left, Right);
+      if (state) {
+        // The return value is the comparison result, which we don't know.
+        unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+        SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
+        state = state->BindExpr(CE, CmpV);
+        C.addTransition(state);
+      }
+    }
+  }
+}
+
+void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
+  // size_t strlen(const char *s);
+  const GRState *state = C.getState();
+  const Expr *Arg = CE->getArg(0);
+  SVal ArgVal = state->getSVal(Arg);
+
+  // Check that the argument is non-null.
+  state = checkNonNull(C, state, Arg, ArgVal);
+
+  if (state) {
+    SVal strLength = getCStringLength(C, state, Arg, ArgVal);
+
+    // If the argument isn't a valid C string, there's no valid state to
+    // transition to.
+    if (strLength.isUndef())
+      return;
+
+    // If getCStringLength couldn't figure out the length, conjure a return
+    // value, so it can be used in constraints, at least.
+    if (strLength.isUnknown()) {
+      unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+      strLength = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+    }
+
+    // Bind the return value.
+    state = state->BindExpr(CE, strLength);
+    C.addTransition(state);
+  }
+}
+
+void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) {
+  // char *strcpy(char *restrict dst, const char *restrict src);
+  evalStrcpyCommon(C, CE, /* returnEnd = */ false);
+}
+
+void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) {
+  // char *stpcpy(char *restrict dst, const char *restrict src);
+  evalStrcpyCommon(C, CE, /* returnEnd = */ true);
+}
+
+void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
+                                      bool returnEnd) {
+  const GRState *state = C.getState();
+
+  // Check that the destination is non-null
+  const Expr *Dst = CE->getArg(0);
+  SVal DstVal = state->getSVal(Dst);
+
+  state = checkNonNull(C, state, Dst, DstVal);
+  if (!state)
+    return;
+
+  // Check that the source is non-null.
+  const Expr *srcExpr = CE->getArg(1);
+  SVal srcVal = state->getSVal(srcExpr);
+  state = checkNonNull(C, state, srcExpr, srcVal);
+  if (!state)
+    return;
+
+  // Get the string length of the source.
+  SVal strLength = getCStringLength(C, state, srcExpr, srcVal);
+
+  // If the source isn't a valid C string, give up.
+  if (strLength.isUndef())
+    return;
+
+  SVal Result = (returnEnd ? UnknownVal() : DstVal);
+
+  // If the destination is a MemRegion, try to check for a buffer overflow and
+  // record the new string length.
+  if (loc::MemRegionVal *dstRegVal = dyn_cast<loc::MemRegionVal>(&DstVal)) {
+    // If the length is known, we can check for an overflow.
+    if (NonLoc *knownStrLength = dyn_cast<NonLoc>(&strLength)) {
+      SVal lastElement =
+        C.getSValBuilder().evalBinOpLN(state, BO_Add, *dstRegVal,
+                                       *knownStrLength, Dst->getType());
+
+      state = CheckLocation(C, state, Dst, lastElement, /* IsDst = */ true);
+      if (!state)
+        return;
+
+      // If this is a stpcpy-style copy, the last element is the return value.
+      if (returnEnd)
+        Result = lastElement;
+    }
+
+    // Invalidate the destination. This must happen before we set the C string
+    // length because invalidation will clear the length.
+    // FIXME: Even if we can't perfectly model the copy, we should see if we
+    // can use LazyCompoundVals to copy the source values into the destination.
+    // This would probably remove any existing bindings past the end of the
+    // string, but that's still an improvement over blank invalidation.
+    state = InvalidateBuffer(C, state, Dst, *dstRegVal);
+
+    // Set the C string length of the destination.
+    state = setCStringLength(state, dstRegVal->getRegion(), strLength);
+  }
+
+  // If this is a stpcpy-style copy, but we were unable to check for a buffer
+  // overflow, we still need a result. Conjure a return value.
+  if (returnEnd && Result.isUnknown()) {
+    SValBuilder &svalBuilder = C.getSValBuilder();
+    unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+    strLength = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
+  }
+
+  // Set the return value.
+  state = state->BindExpr(CE, Result);
+  C.addTransition(state);
+}
+
+//===----------------------------------------------------------------------===//
+// The driver method, and other Checker callbacks.
+//===----------------------------------------------------------------------===//
+
+bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+  // Get the callee.  All the functions we care about are C functions
+  // with simple identifiers.
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
+
+  if (!FD)
+    return false;
+
+  // Get the name of the callee. If it's a builtin, strip off the prefix.
+  IdentifierInfo *II = FD->getIdentifier();
+  if (!II)   // if no identifier, not a simple C function
+    return false;
+  llvm::StringRef Name = II->getName();
+  if (Name.startswith("__builtin_"))
+    Name = Name.substr(10);
+
+  FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
+    .Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
+    .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
+    .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
+    .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
+    .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
+    .Case("strlen", &CStringChecker::evalstrLength)
+    .Case("bcopy", &CStringChecker::evalBcopy)
+    .Default(NULL);
+
+  // If the callee isn't a string function, let another checker handle it.
+  if (!evalFunction)
+    return false;
+
+  // Check and evaluate the call.
+  (this->*evalFunction)(C, CE);
+  return true;
+}
+
+void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+  // Record string length for char a[] = "abc";
+  const GRState *state = C.getState();
+
+  for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
+       I != E; ++I) {
+    const VarDecl *D = dyn_cast<VarDecl>(*I);
+    if (!D)
+      continue;
+
+    // FIXME: Handle array fields of structs.
+    if (!D->getType()->isArrayType())
+      continue;
+
+    const Expr *Init = D->getInit();
+    if (!Init)
+      continue;
+    if (!isa<StringLiteral>(Init))
+      continue;
+
+    Loc VarLoc = state->getLValue(D, C.getPredecessor()->getLocationContext());
+    const MemRegion *MR = VarLoc.getAsRegion();
+    if (!MR)
+      continue;
+
+    SVal StrVal = state->getSVal(Init);
+    assert(StrVal.isValid() && "Initializer string is unknown or undefined");
+    DefinedOrUnknownSVal strLength
+      = cast<DefinedOrUnknownSVal>(getCStringLength(C, state, Init, StrVal));
+
+    state = state->set<CStringLength>(MR, strLength);
+  }
+
+  C.addTransition(state);
+}
+
+bool CStringChecker::WantsRegionChangeUpdate(const GRState *state) {
+  CStringLength::EntryMap Entries = state->get<CStringLength>();
+  return !Entries.isEmpty();
+}
+
+const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
+                                                 const MemRegion * const *Begin,
+                                                 const MemRegion * const *End,
+                                                 bool *) {
+  CStringLength::EntryMap Entries = state->get<CStringLength>();
+  if (Entries.isEmpty())
+    return state;
+
+  llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
+  llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
+
+  // First build sets for the changed regions and their super-regions.
+  for ( ; Begin != End; ++Begin) {
+    const MemRegion *MR = *Begin;
+    Invalidated.insert(MR);
+
+    SuperRegions.insert(MR);
+    while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
+      MR = SR->getSuperRegion();
+      SuperRegions.insert(MR);
+    }
+  }
+
+  CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
+
+  // Then loop over the entries in the current state.
+  for (CStringLength::EntryMap::iterator I = Entries.begin(),
+       E = Entries.end(); I != E; ++I) {
+    const MemRegion *MR = I.getKey();
+
+    // Is this entry for a super-region of a changed region?
+    if (SuperRegions.count(MR)) {
+      Entries = F.remove(Entries, MR);
+      continue;
+    }
+
+    // Is this entry for a sub-region of a changed region?
+    const MemRegion *Super = MR;
+    while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
+      Super = SR->getSuperRegion();
+      if (Invalidated.count(Super)) {
+        Entries = F.remove(Entries, MR);
+        break;
+      }
+    }
+  }
+
+  return state->set<CStringLength>(Entries);
+}
+
+void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
+  // Mark all symbols in our string length map as valid.
+  CStringLength::EntryMap Entries = state->get<CStringLength>();
+
+  for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+       I != E; ++I) {
+    SVal Len = I.getData();
+    if (SymbolRef Sym = Len.getAsSymbol())
+      SR.markInUse(Sym);
+  }
+}
+
+void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
+  if (!SR.hasDeadSymbols())
+    return;
+
+  const GRState *state = C.getState();
+  CStringLength::EntryMap Entries = state->get<CStringLength>();
+  if (Entries.isEmpty())
+    return;
+
+  CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
+  for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
+       I != E; ++I) {
+    SVal Len = I.getData();
+    if (SymbolRef Sym = Len.getAsSymbol()) {
+      if (SR.isDead(Sym))
+        Entries = F.remove(Entries, I.getKey());
+    }
+  }
+
+  state = state->set<CStringLength>(Entries);
+  C.generateNode(state);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp
new file mode 100644 (file)
index 0000000..2998406
--- /dev/null
@@ -0,0 +1,350 @@
+//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines CallAndMessageChecker, a builtin checker that checks for various
+// errors of call and objc message expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class CallAndMessageChecker
+  : public CheckerVisitor<CallAndMessageChecker> {
+  BugType *BT_call_null;
+  BugType *BT_call_undef;
+  BugType *BT_call_arg;
+  BugType *BT_msg_undef;
+  BugType *BT_msg_arg;
+  BugType *BT_msg_ret;
+public:
+  CallAndMessageChecker() :
+    BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
+    BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
+
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+  bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
+
+private:
+  bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
+                          const char *BT_desc, BugType *&BT);
+
+  void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
+  void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+                          ExplodedNode *N);
+
+  void HandleNilReceiver(CheckerContext &C, const GRState *state,
+                         const ObjCMessageExpr *ME);
+
+  void LazyInit_BT(const char *desc, BugType *&BT) {
+    if (!BT)
+      BT = new BuiltinBug(desc);
+  }
+};
+} // end anonymous namespace
+
+void ento::RegisterCallAndMessageChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new CallAndMessageChecker());
+}
+
+void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
+                                        const CallExpr *CE) {
+  ExplodedNode *N = C.generateSink();
+  if (!N)
+    return;
+
+  EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+  R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                       bugreporter::GetCalleeExpr(N));
+  C.EmitReport(R);
+}
+
+bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
+                                               const Expr *Ex,
+                                               const char *BT_desc,
+                                               BugType *&BT) {
+
+  const SVal &V = C.getState()->getSVal(Ex);
+
+  if (V.isUndef()) {
+    if (ExplodedNode *N = C.generateSink()) {
+      LazyInit_BT(BT_desc, BT);
+
+      // Generate a report for this bug.
+      EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+      R->addRange(Ex->getSourceRange());
+      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+      C.EmitReport(R);
+    }
+    return true;
+  }
+
+  if (const nonloc::LazyCompoundVal *LV =
+        dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+    class FindUninitializedField {
+    public:
+      llvm::SmallVector<const FieldDecl *, 10> FieldChain;
+    private:
+      ASTContext &C;
+      StoreManager &StoreMgr;
+      MemRegionManager &MrMgr;
+      Store store;
+    public:
+      FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
+                             MemRegionManager &mrMgr, Store s)
+      : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
+
+      bool Find(const TypedRegion *R) {
+        QualType T = R->getValueType();
+        if (const RecordType *RT = T->getAsStructureType()) {
+          const RecordDecl *RD = RT->getDecl()->getDefinition();
+          assert(RD && "Referred record has no definition");
+          for (RecordDecl::field_iterator I =
+               RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
+            const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
+            FieldChain.push_back(*I);
+            T = (*I)->getType();
+            if (T->getAsStructureType()) {
+              if (Find(FR))
+                return true;
+            }
+            else {
+              const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
+              if (V.isUndef())
+                return true;
+            }
+            FieldChain.pop_back();
+          }
+        }
+
+        return false;
+      }
+    };
+
+    const LazyCompoundValData *D = LV->getCVData();
+    FindUninitializedField F(C.getASTContext(),
+                             C.getState()->getStateManager().getStoreManager(),
+                             C.getSValBuilder().getRegionManager(),
+                             D->getStore());
+
+    if (F.Find(D->getRegion())) {
+      if (ExplodedNode *N = C.generateSink()) {
+        LazyInit_BT(BT_desc, BT);
+        llvm::SmallString<512> Str;
+        llvm::raw_svector_ostream os(Str);
+        os << "Passed-by-value struct argument contains uninitialized data";
+
+        if (F.FieldChain.size() == 1)
+          os << " (e.g., field: '" << F.FieldChain[0] << "')";
+        else {
+          os << " (e.g., via the field chain: '";
+          bool first = true;
+          for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
+               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
+            if (first)
+              first = false;
+            else
+              os << '.';
+            os << *DI;
+          }
+          os << "')";
+        }
+
+        // Generate a report for this bug.
+        EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+        R->addRange(Ex->getSourceRange());
+
+        // FIXME: enhance track back for uninitialized value for arbitrary
+        // memregions
+        C.EmitReport(R);
+      }
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
+                                             const CallExpr *CE){
+
+  const Expr *Callee = CE->getCallee()->IgnoreParens();
+  SVal L = C.getState()->getSVal(Callee);
+
+  if (L.isUndef()) {
+    if (!BT_call_undef)
+      BT_call_undef =
+        new BuiltinBug("Called function pointer is an uninitalized pointer value");
+    EmitBadCall(BT_call_undef, C, CE);
+    return;
+  }
+
+  if (isa<loc::ConcreteInt>(L)) {
+    if (!BT_call_null)
+      BT_call_null =
+        new BuiltinBug("Called function pointer is null (null dereference)");
+    EmitBadCall(BT_call_null, C, CE);
+  }
+
+  for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+       I != E; ++I)
+    if (PreVisitProcessArg(C, *I,
+                           "Function call argument is an uninitialized value",
+                           BT_call_arg))
+      return;
+}
+
+void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+                                                    const ObjCMessageExpr *ME) {
+
+  const GRState *state = C.getState();
+
+  // FIXME: Handle 'super'?
+  if (const Expr *receiver = ME->getInstanceReceiver())
+    if (state->getSVal(receiver).isUndef()) {
+      if (ExplodedNode *N = C.generateSink()) {
+        if (!BT_msg_undef)
+          BT_msg_undef =
+            new BuiltinBug("Receiver in message expression is an uninitialized value");
+        EnhancedBugReport *R =
+          new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+        R->addRange(receiver->getSourceRange());
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                             receiver);
+        C.EmitReport(R);
+      }
+      return;
+    }
+
+  // Check for any arguments that are uninitialized/undefined.
+  for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
+         E = ME->arg_end(); I != E; ++I)
+    if (PreVisitProcessArg(C, *I,
+                           "Argument in message expression "
+                           "is an uninitialized value", BT_msg_arg))
+        return;
+}
+
+bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
+                                            const ObjCMessageExpr *ME) {
+  HandleNilReceiver(C, C.getState(), ME);
+  return true; // Nil receiver is not handled elsewhere.
+}
+
+void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
+                                               const ObjCMessageExpr *ME,
+                                               ExplodedNode *N) {
+
+  if (!BT_msg_ret)
+    BT_msg_ret =
+      new BuiltinBug("Receiver in message expression is "
+                     "'nil' and returns a garbage value");
+
+  llvm::SmallString<200> buf;
+  llvm::raw_svector_ostream os(buf);
+  os << "The receiver of message '" << ME->getSelector().getAsString()
+     << "' is nil and returns a value of type '"
+     << ME->getType().getAsString() << "' that will be garbage";
+
+  EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
+  if (const Expr *receiver = ME->getInstanceReceiver()) {
+    report->addRange(receiver->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                              receiver);
+  }
+  C.EmitReport(report);
+}
+
+static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
+  return triple.getVendor() == llvm::Triple::Apple &&
+         (triple.getDarwinMajorNumber() >= 9 || 
+          triple.getArch() == llvm::Triple::arm || 
+          triple.getArch() == llvm::Triple::thumb);
+}
+
+void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
+                                              const GRState *state,
+                                              const ObjCMessageExpr *ME) {
+
+  // Check the return type of the message expression.  A message to nil will
+  // return different values depending on the return type and the architecture.
+  QualType RetTy = ME->getType();
+
+  ASTContext &Ctx = C.getASTContext();
+  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
+
+  if (CanRetTy->isStructureOrClassType()) {
+    // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
+    // have the "use of undefined value" be smarter about where the
+    // undefined value came from.
+    if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+      if (ExplodedNode* N = C.generateSink(state))
+        emitNilReceiverBug(C, ME, N);
+      return;
+    }
+
+    // The result is not consumed by a surrounding expression.  Just propagate
+    // the current state.
+    C.addTransition(state);
+    return;
+  }
+
+  // Other cases: check if the return type is smaller than void*.
+  if (CanRetTy != Ctx.VoidTy &&
+      C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+    // Compute: sizeof(void *) and sizeof(return type)
+    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
+
+    if (voidPtrSize < returnTypeSize &&
+        !(supportsNilWithFloatRet(Ctx.Target.getTriple()) &&
+          (Ctx.FloatTy == CanRetTy ||
+           Ctx.DoubleTy == CanRetTy ||
+           Ctx.LongDoubleTy == CanRetTy ||
+           Ctx.LongLongTy == CanRetTy ||
+           Ctx.UnsignedLongLongTy == CanRetTy))) {
+      if (ExplodedNode* N = C.generateSink(state))
+        emitNilReceiverBug(C, ME, N);
+      return;
+    }
+
+    // Handle the safe cases where the return value is 0 if the
+    // receiver is nil.
+    //
+    // FIXME: For now take the conservative approach that we only
+    // return null values if we *know* that the receiver is nil.
+    // This is because we can have surprises like:
+    //
+    //   ... = [[NSScreens screens] objectAtIndex:0];
+    //
+    // What can happen is that [... screens] could return nil, but
+    // it most likely isn't nil.  We should assume the semantics
+    // of this case unless we have *a lot* more knowledge.
+    //
+    SVal V = C.getSValBuilder().makeZeroVal(ME->getType());
+    C.generateNode(state->BindExpr(ME, V));
+    return;
+  }
+
+  C.addTransition(state);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp
new file mode 100644 (file)
index 0000000..9329ea3
--- /dev/null
@@ -0,0 +1,91 @@
+//=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
+// whether the size of the symbolic region is a multiple of the size of T.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/CharUnits.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "ExprEngineInternalChecks.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class CastSizeChecker : public CheckerVisitor<CastSizeChecker> {
+  BuiltinBug *BT;
+public:
+  CastSizeChecker() : BT(0) {}
+  static void *getTag();
+  void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+};
+}
+
+void *CastSizeChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
+  const Expr *E = CE->getSubExpr();
+  ASTContext &Ctx = C.getASTContext();
+  QualType ToTy = Ctx.getCanonicalType(CE->getType());
+  PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
+
+  if (!ToPTy)
+    return;
+
+  QualType ToPointeeTy = ToPTy->getPointeeType();
+
+  // Only perform the check if 'ToPointeeTy' is a complete type.
+  if (ToPointeeTy->isIncompleteType())
+    return;
+
+  const GRState *state = C.getState();
+  const MemRegion *R = state->getSVal(E).getAsRegion();
+  if (R == 0)
+    return;
+
+  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+  if (SR == 0)
+    return;
+
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  SVal extent = SR->getExtent(svalBuilder);
+  const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent);
+  if (!extentInt)
+    return;
+
+  CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue());
+  CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
+
+  // Ignore void, and a few other un-sizeable types.
+  if (typeSize.isZero())
+    return;
+
+  if (regionSize % typeSize != 0) {
+    if (ExplodedNode *errorNode = C.generateSink()) {
+      if (!BT)
+        BT = new BuiltinBug("Cast region with wrong size.",
+                            "Cast a region whose size is not a multiple of the"
+                            " destination type size.");
+      RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(),
+                                               errorNode);
+      R->addRange(CE->getSourceRange());
+      C.EmitReport(R);
+    }
+  }
+}
+
+
+void ento::RegisterCastSizeChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new CastSizeChecker());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp
new file mode 100644 (file)
index 0000000..dd6ac7e
--- /dev/null
@@ -0,0 +1,79 @@
+//=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines CastToStructChecker, a builtin checker that checks for
+// cast from non-struct pointer to struct pointer.
+// This check corresponds to CWE-588.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "ExprEngineInternalChecks.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class CastToStructChecker 
+  : public CheckerVisitor<CastToStructChecker> {
+  BuiltinBug *BT;
+public:
+  CastToStructChecker() : BT(0) {}
+  static void *getTag();
+  void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+};
+}
+
+void *CastToStructChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
+                                           const CastExpr *CE) {
+  const Expr *E = CE->getSubExpr();
+  ASTContext &Ctx = C.getASTContext();
+  QualType OrigTy = Ctx.getCanonicalType(E->getType());
+  QualType ToTy = Ctx.getCanonicalType(CE->getType());
+
+  PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
+  PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
+
+  if (!ToPTy || !OrigPTy)
+    return;
+
+  QualType OrigPointeeTy = OrigPTy->getPointeeType();
+  QualType ToPointeeTy = ToPTy->getPointeeType();
+
+  if (!ToPointeeTy->isStructureOrClassType())
+    return;
+
+  // We allow cast from void*.
+  if (OrigPointeeTy->isVoidType())
+    return;
+
+  // Now the cast-to-type is struct pointer, the original type is not void*.
+  if (!OrigPointeeTy->isRecordType()) {
+    if (ExplodedNode *N = C.generateNode()) {
+      if (!BT)
+        BT = new BuiltinBug("Cast from non-struct type to struct type",
+                            "Casting a non-structure type to a structure type "
+                            "and accessing a field can lead to memory access "
+                            "errors or data corruption.");
+      RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
+      R->addRange(CE->getSourceRange());
+      C.EmitReport(R);
+    }
+  }
+}
+
+void ento::RegisterCastToStructChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new CastToStructChecker());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp
new file mode 100644 (file)
index 0000000..1fe40c5
--- /dev/null
@@ -0,0 +1,290 @@
+//==- DeadStores.cpp - Check for stores to dead variables --------*- 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 a DeadStores, a flow-sensitive checker that looks for
+//  stores to variables that are no longer live.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ParentMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class DeadStoreObs : public LiveVariables::ObserverTy {
+  ASTContext &Ctx;
+  BugReporter& BR;
+  ParentMap& Parents;
+  llvm::SmallPtrSet<VarDecl*, 20> Escaped;
+
+  enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
+
+public:
+  DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents,
+               llvm::SmallPtrSet<VarDecl*, 20> &escaped)
+    : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {}
+
+  virtual ~DeadStoreObs() {}
+
+  void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
+    if (Escaped.count(V))
+      return;
+
+    std::string name = V->getNameAsString();
+
+    const char* BugType = 0;
+    std::string msg;
+
+    switch (dsk) {
+      default:
+        assert(false && "Impossible dead store type.");
+
+      case DeadInit:
+        BugType = "Dead initialization";
+        msg = "Value stored to '" + name +
+          "' during its initialization is never read";
+        break;
+
+      case DeadIncrement:
+        BugType = "Dead increment";
+      case Standard:
+        if (!BugType) BugType = "Dead assignment";
+        msg = "Value stored to '" + name + "' is never read";
+        break;
+
+      case Enclosing:
+        BugType = "Dead nested assignment";
+        msg = "Although the value stored to '" + name +
+          "' is used in the enclosing expression, the value is never actually"
+          " read from '" + name + "'";
+        break;
+    }
+
+    BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
+  }
+
+  void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
+                    DeadStoreKind dsk,
+                    const LiveVariables::AnalysisDataTy& AD,
+                    const LiveVariables::ValTy& Live) {
+
+    if (!VD->hasLocalStorage())
+      return;
+    // Reference types confuse the dead stores checker.  Skip them
+    // for now.
+    if (VD->getType()->getAs<ReferenceType>())
+      return;
+
+    if (!Live(VD, AD) && 
+        !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
+      Report(VD, dsk, Ex->getSourceRange().getBegin(),
+             Val->getSourceRange());
+  }
+
+  void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
+                    const LiveVariables::AnalysisDataTy& AD,
+                    const LiveVariables::ValTy& Live) {
+    if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
+      CheckVarDecl(VD, DR, Val, dsk, AD, Live);
+  }
+
+  bool isIncrement(VarDecl* VD, BinaryOperator* B) {
+    if (B->isCompoundAssignmentOp())
+      return true;
+
+    Expr* RHS = B->getRHS()->IgnoreParenCasts();
+    BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
+
+    if (!BRHS)
+      return false;
+
+    DeclRefExpr *DR;
+
+    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
+      if (DR->getDecl() == VD)
+        return true;
+
+    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
+      if (DR->getDecl() == VD)
+        return true;
+
+    return false;
+  }
+
+  virtual void ObserveStmt(Stmt* S,
+                           const LiveVariables::AnalysisDataTy& AD,
+                           const LiveVariables::ValTy& Live) {
+
+    // Skip statements in macros.
+    if (S->getLocStart().isMacroID())
+      return;
+
+    if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+      if (!B->isAssignmentOp()) return; // Skip non-assignments.
+
+      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
+        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+          // Special case: check for assigning null to a pointer.
+          //  This is a common form of defensive programming.
+          QualType T = VD->getType();
+          if (T->isPointerType() || T->isObjCObjectPointerType()) {
+            if (B->getRHS()->isNullPointerConstant(Ctx,
+                                              Expr::NPC_ValueDependentIsNull))
+              return;
+          }
+
+          Expr* RHS = B->getRHS()->IgnoreParenCasts();
+          // Special case: self-assignments.  These are often used to shut up
+          //  "unused variable" compiler warnings.
+          if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
+            if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
+              return;
+
+          // Otherwise, issue a warning.
+          DeadStoreKind dsk = Parents.isConsumedExpr(B)
+                              ? Enclosing
+                              : (isIncrement(VD,B) ? DeadIncrement : Standard);
+
+          CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
+        }
+    }
+    else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
+      if (!U->isIncrementOp())
+        return;
+
+      // Handle: ++x within a subexpression.  The solution is not warn
+      //  about preincrements to dead variables when the preincrement occurs
+      //  as a subexpression.  This can lead to false negatives, e.g. "(++x);"
+      //  A generalized dead code checker should find such issues.
+      if (U->isPrefix() && Parents.isConsumedExpr(U))
+        return;
+
+      Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
+
+      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
+        CheckDeclRef(DR, U, DeadIncrement, AD, Live);
+    }
+    else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
+      // Iterate through the decls.  Warn if any initializers are complex
+      // expressions that are not live (never used).
+      for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
+           DI != DE; ++DI) {
+
+        VarDecl* V = dyn_cast<VarDecl>(*DI);
+
+        if (!V)
+          continue;
+          
+        if (V->hasLocalStorage()) {          
+          // Reference types confuse the dead stores checker.  Skip them
+          // for now.
+          if (V->getType()->getAs<ReferenceType>())
+            return;
+            
+          if (Expr* E = V->getInit()) {
+            // Don't warn on C++ objects (yet) until we can show that their
+            // constructors/destructors don't have side effects.
+            if (isa<CXXConstructExpr>(E))
+              return;
+
+            if (isa<ExprWithCleanups>(E))
+              return;
+            
+            // A dead initialization is a variable that is dead after it
+            // is initialized.  We don't flag warnings for those variables
+            // marked 'unused'.
+            if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
+              // Special case: check for initializations with constants.
+              //
+              //  e.g. : int x = 0;
+              //
+              // If x is EVER assigned a new value later, don't issue
+              // a warning.  This is because such initialization can be
+              // due to defensive programming.
+              if (E->isConstantInitializer(Ctx, false))
+                return;
+
+              if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+                if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+                  // Special case: check for initialization from constant
+                  //  variables.
+                  //
+                  //  e.g. extern const int MyConstant;
+                  //       int x = MyConstant;
+                  //
+                  if (VD->hasGlobalStorage() &&
+                      VD->getType().isConstQualified())
+                    return;
+                  // Special case: check for initialization from scalar
+                  //  parameters.  This is often a form of defensive
+                  //  programming.  Non-scalars are still an error since
+                  //  because it more likely represents an actual algorithmic
+                  //  bug.
+                  if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
+                    return;
+                }
+
+              Report(V, DeadInit, V->getLocation(), E->getSourceRange());
+            }
+          }
+        }
+      }
+  }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Driver function to invoke the Dead-Stores checker on a CFG.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
+  CFG *cfg;
+public:
+  FindEscaped(CFG *c) : cfg(c) {}
+
+  CFG& getCFG() { return *cfg; }
+
+  llvm::SmallPtrSet<VarDecl*, 20> Escaped;
+
+  void VisitUnaryOperator(UnaryOperator* U) {
+    // Check for '&'.  Any VarDecl whose value has its address-taken we
+    // treat as escaped.
+    Expr* E = U->getSubExpr()->IgnoreParenCasts();
+    if (U->getOpcode() == UO_AddrOf)
+      if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
+        if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
+          Escaped.insert(VD);
+          return;
+        }
+    Visit(E);
+  }
+};
+} // end anonymous namespace
+
+
+void ento::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap, 
+                            BugReporter& BR) {
+  FindEscaped FS(&cfg);
+  FS.getCFG().VisitBlockStmts(FS);
+  DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped);
+  L.runOnAllBlocks(cfg, &A);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp
new file mode 100644 (file)
index 0000000..932a6f5
--- /dev/null
@@ -0,0 +1,262 @@
+//==- CheckObjCDealloc.cpp - Check ObjC -dealloc implementation --*- 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 a CheckObjCDealloc, a checker that
+//  analyzes an Objective-C class's implementation to determine if it
+//  correctly implements -dealloc.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+static bool scan_dealloc(Stmt* S, Selector Dealloc) {
+
+  if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+    if (ME->getSelector() == Dealloc) {
+      switch (ME->getReceiverKind()) {
+      case ObjCMessageExpr::Instance: return false;
+      case ObjCMessageExpr::SuperInstance: return true;
+      case ObjCMessageExpr::Class: break;
+      case ObjCMessageExpr::SuperClass: break;
+      }
+    }
+
+  // Recurse to children.
+
+  for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
+    if (*I && scan_dealloc(*I, Dealloc))
+      return true;
+
+  return false;
+}
+
+static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
+                              const ObjCPropertyDecl* PD,
+                              Selector Release,
+                              IdentifierInfo* SelfII,
+                              ASTContext& Ctx) {
+
+  // [mMyIvar release]
+  if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+    if (ME->getSelector() == Release)
+      if (ME->getInstanceReceiver())
+        if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
+          if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
+            if (E->getDecl() == ID)
+              return true;
+
+  // [self setMyIvar:nil];
+  if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
+    if (ME->getInstanceReceiver())
+      if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
+        if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
+          if (E->getDecl()->getIdentifier() == SelfII)
+            if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
+                ME->getNumArgs() == 1 &&
+                ME->getArg(0)->isNullPointerConstant(Ctx, 
+                                              Expr::NPC_ValueDependentIsNull))
+              return true;
+
+  // self.myIvar = nil;
+  if (BinaryOperator* BO = dyn_cast<BinaryOperator>(S))
+    if (BO->isAssignmentOp())
+      if (ObjCPropertyRefExpr* PRE =
+           dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
+        if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD)
+            if (BO->getRHS()->isNullPointerConstant(Ctx, 
+                                            Expr::NPC_ValueDependentIsNull)) {
+              // This is only a 'release' if the property kind is not
+              // 'assign'.
+              return PD->getSetterKind() != ObjCPropertyDecl::Assign;;
+            }
+
+  // Recurse to children.
+  for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
+    if (*I && scan_ivar_release(*I, ID, PD, Release, SelfII, Ctx))
+      return true;
+
+  return false;
+}
+
+void ento::CheckObjCDealloc(const ObjCImplementationDecl* D,
+                          const LangOptions& LOpts, BugReporter& BR) {
+
+  assert (LOpts.getGCMode() != LangOptions::GCOnly);
+
+  ASTContext& Ctx = BR.getContext();
+  const ObjCInterfaceDecl* ID = D->getClassInterface();
+
+  // Does the class contain any ivars that are pointers (or id<...>)?
+  // If not, skip the check entirely.
+  // NOTE: This is motivated by PR 2517:
+  //        http://llvm.org/bugs/show_bug.cgi?id=2517
+
+  bool containsPointerIvar = false;
+
+  for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
+       I!=E; ++I) {
+
+    ObjCIvarDecl* ID = *I;
+    QualType T = ID->getType();
+
+    if (!T->isObjCObjectPointerType() ||
+        ID->getAttr<IBOutletAttr>() || // Skip IBOutlets.
+        ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
+      continue;
+
+    containsPointerIvar = true;
+    break;
+  }
+
+  if (!containsPointerIvar)
+    return;
+
+  // Determine if the class subclasses NSObject.
+  IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
+  IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");
+
+
+  for ( ; ID ; ID = ID->getSuperClass()) {
+    IdentifierInfo *II = ID->getIdentifier();
+
+    if (II == NSObjectII)
+      break;
+
+    // FIXME: For now, ignore classes that subclass SenTestCase, as these don't
+    // need to implement -dealloc.  They implement tear down in another way,
+    // which we should try and catch later.
+    //  http://llvm.org/bugs/show_bug.cgi?id=3187
+    if (II == SenTestCaseII)
+      return;
+  }
+
+  if (!ID)
+    return;
+
+  // Get the "dealloc" selector.
+  IdentifierInfo* II = &Ctx.Idents.get("dealloc");
+  Selector S = Ctx.Selectors.getSelector(0, &II);
+  ObjCMethodDecl* MD = 0;
+
+  // Scan the instance methods for "dealloc".
+  for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
+       E = D->instmeth_end(); I!=E; ++I) {
+
+    if ((*I)->getSelector() == S) {
+      MD = *I;
+      break;
+    }
+  }
+
+  if (!MD) { // No dealloc found.
+
+    const char* name = LOpts.getGCMode() == LangOptions::NonGC
+                       ? "missing -dealloc"
+                       : "missing -dealloc (Hybrid MM, non-GC)";
+
+    std::string buf;
+    llvm::raw_string_ostream os(buf);
+    os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
+
+    BR.EmitBasicReport(name, os.str(), D->getLocStart());
+    return;
+  }
+
+  // dealloc found.  Scan for missing [super dealloc].
+  if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) {
+
+    const char* name = LOpts.getGCMode() == LangOptions::NonGC
+                       ? "missing [super dealloc]"
+                       : "missing [super dealloc] (Hybrid MM, non-GC)";
+
+    std::string buf;
+    llvm::raw_string_ostream os(buf);
+    os << "The 'dealloc' instance method in Objective-C class '" << D
+       << "' does not send a 'dealloc' message to its super class"
+           " (missing [super dealloc])";
+
+    BR.EmitBasicReport(name, os.str(), D->getLocStart());
+    return;
+  }
+
+  // Get the "release" selector.
+  IdentifierInfo* RII = &Ctx.Idents.get("release");
+  Selector RS = Ctx.Selectors.getSelector(0, &RII);
+
+  // Get the "self" identifier
+  IdentifierInfo* SelfII = &Ctx.Idents.get("self");
+
+  // Scan for missing and extra releases of ivars used by implementations
+  // of synthesized properties
+  for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
+       E = D->propimpl_end(); I!=E; ++I) {
+
+    // We can only check the synthesized properties
+    if ((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+      continue;
+
+    ObjCIvarDecl* ID = (*I)->getPropertyIvarDecl();
+    if (!ID)
+      continue;
+
+    QualType T = ID->getType();
+    if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
+      continue;
+
+    const ObjCPropertyDecl* PD = (*I)->getPropertyDecl();
+    if (!PD)
+      continue;
+
+    // ivars cannot be set via read-only properties, so we'll skip them
+    if (PD->isReadOnly())
+       continue;
+
+    // ivar must be released if and only if the kind of setter was not 'assign'
+    bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
+    if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
+       != requiresRelease) {
+      const char *name;
+      const char* category = "Memory (Core Foundation/Objective-C)";
+
+      std::string buf;
+      llvm::raw_string_ostream os(buf);
+
+      if (requiresRelease) {
+        name = LOpts.getGCMode() == LangOptions::NonGC
+               ? "missing ivar release (leak)"
+               : "missing ivar release (Hybrid MM, non-GC)";
+
+        os << "The '" << ID
+           << "' instance variable was retained by a synthesized property but "
+              "wasn't released in 'dealloc'";
+      } else {
+        name = LOpts.getGCMode() == LangOptions::NonGC
+               ? "extra ivar release (use-after-release)"
+               : "extra ivar release (Hybrid MM, non-GC)";
+
+        os << "The '" << ID
+           << "' instance variable was not retained by a synthesized property "
+              "but was released in 'dealloc'";
+      }
+
+      BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation());
+    }
+  }
+}
+
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp
new file mode 100644 (file)
index 0000000..57e388f
--- /dev/null
@@ -0,0 +1,120 @@
+//=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- 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 a CheckObjCInstMethSignature, a flow-insenstive check
+//  that determines if an Objective-C class interface incorrectly redefines
+//  the method signature in a subclass.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/ASTContext.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
+                               ASTContext& C) {
+
+  // Right now don't compare the compatibility of pointers.  That involves
+  // looking at subtyping relationships.  FIXME: Future patch.
+  if (Derived->isAnyPointerType() &&  Ancestor->isAnyPointerType())
+    return true;
+
+  return C.typesAreCompatible(Derived, Ancestor);
+}
+
+static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
+                               const ObjCMethodDecl *MethAncestor,
+                               BugReporter &BR, ASTContext &Ctx,
+                               const ObjCImplementationDecl *ID) {
+
+  QualType ResDerived  = MethDerived->getResultType();
+  QualType ResAncestor = MethAncestor->getResultType();
+
+  if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
+    std::string sbuf;
+    llvm::raw_string_ostream os(sbuf);
+
+    os << "The Objective-C class '"
+       << MethDerived->getClassInterface()
+       << "', which is derived from class '"
+       << MethAncestor->getClassInterface()
+       << "', defines the instance method '"
+       << MethDerived->getSelector().getAsString()
+       << "' whose return type is '"
+       << ResDerived.getAsString()
+       << "'.  A method with the same name (same selector) is also defined in "
+          "class '"
+       << MethAncestor->getClassInterface()
+       << "' and has a return type of '"
+       << ResAncestor.getAsString()
+       << "'.  These two types are incompatible, and may result in undefined "
+          "behavior for clients of these classes.";
+
+    BR.EmitBasicReport("Incompatible instance method return type",
+                       os.str(), MethDerived->getLocStart());
+  }
+}
+
+void ento::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
+                                    BugReporter& BR) {
+
+  const ObjCInterfaceDecl* D = ID->getClassInterface();
+  const ObjCInterfaceDecl* C = D->getSuperClass();
+
+  if (!C)
+    return;
+
+  ASTContext& Ctx = BR.getContext();
+
+  // Build a DenseMap of the methods for quick querying.
+  typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
+  MapTy IMeths;
+  unsigned NumMethods = 0;
+
+  for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(),
+       E=ID->instmeth_end(); I!=E; ++I) {
+
+    ObjCMethodDecl* M = *I;
+    IMeths[M->getSelector()] = M;
+    ++NumMethods;
+  }
+
+  // Now recurse the class hierarchy chain looking for methods with the
+  // same signatures.
+  while (C && NumMethods) {
+    for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(),
+         E=C->instmeth_end(); I!=E; ++I) {
+
+      ObjCMethodDecl* M = *I;
+      Selector S = M->getSelector();
+
+      MapTy::iterator MI = IMeths.find(S);
+
+      if (MI == IMeths.end() || MI->second == 0)
+        continue;
+
+      --NumMethods;
+      ObjCMethodDecl* MethDerived = MI->second;
+      MI->second = 0;
+
+      CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
+    }
+
+    C = C->getSuperClass();
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp
new file mode 100644 (file)
index 0000000..b30e985
--- /dev/null
@@ -0,0 +1,503 @@
+//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- 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 a set of flow-insensitive security checks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+static bool isArc4RandomAvailable(const ASTContext &Ctx) {
+  const llvm::Triple &T = Ctx.Target.getTriple();
+  return T.getVendor() == llvm::Triple::Apple ||
+         T.getOS() == llvm::Triple::FreeBSD;
+}
+
+namespace {
+class WalkAST : public StmtVisitor<WalkAST> {
+  BugReporter &BR;
+  IdentifierInfo *II_gets;
+  IdentifierInfo *II_getpw;
+  IdentifierInfo *II_mktemp;
+  enum { num_rands = 9 };
+  IdentifierInfo *II_rand[num_rands];
+  IdentifierInfo *II_random;
+  enum { num_setids = 6 };
+  IdentifierInfo *II_setid[num_setids];
+
+  const bool CheckRand;
+
+public:
+  WalkAST(BugReporter &br) : BR(br),
+                             II_gets(0), II_getpw(0), II_mktemp(0),
+                             II_rand(), II_random(0), II_setid(),
+                 CheckRand(isArc4RandomAvailable(BR.getContext())) {}
+
+  // Statement visitor methods.
+  void VisitCallExpr(CallExpr *CE);
+  void VisitForStmt(ForStmt *S);
+  void VisitCompoundStmt (CompoundStmt *S);
+  void VisitStmt(Stmt *S) { VisitChildren(S); }
+
+  void VisitChildren(Stmt *S);
+
+  // Helpers.
+  IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
+
+  // Checker-specific methods.
+  void CheckLoopConditionForFloat(const ForStmt *FS);
+  void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
+  void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
+  void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
+  void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
+  void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
+  void CheckUncheckedReturnValue(CallExpr *CE);
+};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Helper methods.
+//===----------------------------------------------------------------------===//
+
+IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
+  if (!II)
+    II = &BR.getContext().Idents.get(str);
+
+  return II;
+}
+
+//===----------------------------------------------------------------------===//
+// AST walking.
+//===----------------------------------------------------------------------===//
+
+void WalkAST::VisitChildren(Stmt *S) {
+  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+    if (Stmt *child = *I)
+      Visit(child);
+}
+
+void WalkAST::VisitCallExpr(CallExpr *CE) {
+  if (const FunctionDecl *FD = CE->getDirectCallee()) {
+    CheckCall_gets(CE, FD);
+    CheckCall_getpw(CE, FD);
+    CheckCall_mktemp(CE, FD);
+    if (CheckRand) {
+      CheckCall_rand(CE, FD);
+      CheckCall_random(CE, FD);
+    }
+  }
+
+  // Recurse and check children.
+  VisitChildren(CE);
+}
+
+void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
+  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+    if (Stmt *child = *I) {
+      if (CallExpr *CE = dyn_cast<CallExpr>(child))
+        CheckUncheckedReturnValue(CE);
+      Visit(child);
+    }
+}
+
+void WalkAST::VisitForStmt(ForStmt *FS) {
+  CheckLoopConditionForFloat(FS);
+
+  // Recurse and check children.
+  VisitChildren(FS);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: floating poing variable used as loop counter.
+// Originally: <rdar://problem/6336718>
+// Implements: CERT security coding advisory FLP-30.
+//===----------------------------------------------------------------------===//
+
+static const DeclRefExpr*
+GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
+  expr = expr->IgnoreParenCasts();
+
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
+    if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
+          B->getOpcode() == BO_Comma))
+      return NULL;
+
+    if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
+      return lhs;
+
+    if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
+      return rhs;
+
+    return NULL;
+  }
+
+  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
+    const NamedDecl *ND = DR->getDecl();
+    return ND == x || ND == y ? DR : NULL;
+  }
+
+  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
+    return U->isIncrementDecrementOp()
+      ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
+
+  return NULL;
+}
+
+/// CheckLoopConditionForFloat - This check looks for 'for' statements that
+///  use a floating point variable as a loop counter.
+///  CERT: FLP30-C, FLP30-CPP.
+///
+void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
+  // Does the loop have a condition?
+  const Expr *condition = FS->getCond();
+
+  if (!condition)
+    return;
+
+  // Does the loop have an increment?
+  const Expr *increment = FS->getInc();
+
+  if (!increment)
+    return;
+
+  // Strip away '()' and casts.
+  condition = condition->IgnoreParenCasts();
+  increment = increment->IgnoreParenCasts();
+
+  // Is the loop condition a comparison?
+  const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
+
+  if (!B)
+    return;
+
+  // Is this a comparison?
+  if (!(B->isRelationalOp() || B->isEqualityOp()))
+    return;
+
+  // Are we comparing variables?
+  const DeclRefExpr *drLHS =
+    dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
+  const DeclRefExpr *drRHS =
+    dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
+
+  // Does at least one of the variables have a floating point type?
+  drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
+  drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL;
+
+  if (!drLHS && !drRHS)
+    return;
+
+  const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
+  const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
+
+  if (!vdLHS && !vdRHS)
+    return;
+
+  // Does either variable appear in increment?
+  const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
+
+  if (!drInc)
+    return;
+
+  // Emit the error.  First figure out which DeclRefExpr in the condition
+  // referenced the compared variable.
+  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
+
+  llvm::SmallVector<SourceRange, 2> ranges;
+  llvm::SmallString<256> sbuf;
+  llvm::raw_svector_ostream os(sbuf);
+
+  os << "Variable '" << drCond->getDecl()->getName()
+     << "' with floating point type '" << drCond->getType().getAsString()
+     << "' should not be used as a loop counter";
+
+  ranges.push_back(drCond->getSourceRange());
+  ranges.push_back(drInc->getSourceRange());
+
+  const char *bugType = "Floating point variable used as loop counter";
+  BR.EmitBasicReport(bugType, "Security", os.str(),
+                     FS->getLocStart(), ranges.data(), ranges.size());
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Any use of 'gets' is insecure.
+// Originally: <rdar://problem/6335715>
+// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
+// CWE-242: Use of Inherently Dangerous Function
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
+  if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
+    return;
+
+  const FunctionProtoType *FPT
+    = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+  if (!FPT)
+    return;
+
+  // Verify that the function takes a single argument.
+  if (FPT->getNumArgs() != 1)
+    return;
+
+  // Is the argument a 'char*'?
+  const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
+  if (!PT)
+    return;
+
+  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+    return;
+
+  // Issue a warning.
+  SourceRange R = CE->getCallee()->getSourceRange();
+  BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
+                     "Security",
+                     "Call to function 'gets' is extremely insecure as it can "
+                     "always result in a buffer overflow",
+                     CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Any use of 'getpwd' is insecure.
+// CWE-477: Use of Obsolete Functions
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
+  if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
+    return;
+
+  const FunctionProtoType *FPT
+    = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+  if (!FPT)
+    return;
+
+  // Verify that the function takes two arguments.
+  if (FPT->getNumArgs() != 2)
+    return;
+
+  // Verify the first argument type is integer.
+  if (!FPT->getArgType(0)->isIntegerType())
+    return;
+
+  // Verify the second argument type is char*.
+  const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
+  if (!PT)
+    return;
+
+  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+    return;
+
+  // Issue a warning.
+  SourceRange R = CE->getCallee()->getSourceRange();
+  BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
+                     "Security",
+                     "The getpw() function is dangerous as it may overflow the "
+                     "provided buffer. It is obsoleted by getpwuid().",
+                     CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
+// CWE-377: Insecure Temporary File
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
+  if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
+    return;
+
+  const FunctionProtoType *FPT
+    = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+  if(!FPT)
+    return;
+
+  // Verify that the funcion takes a single argument.
+  if (FPT->getNumArgs() != 1)
+    return;
+
+  // Verify that the argument is Pointer Type.
+  const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
+  if (!PT)
+    return;
+
+  // Verify that the argument is a 'char*'.
+  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+    return;
+
+  // Issue a waring.
+  SourceRange R = CE->getCallee()->getSourceRange();
+  BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
+                     "Security",
+                     "Call to function 'mktemp' is insecure as it always "
+                     "creates or uses insecure temporary file.  Use 'mkstemp' instead",
+                     CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Linear congruent random number generators should not be used
+// Originally: <rdar://problem/63371000>
+// CWE-338: Use of cryptographically weak prng
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
+  if (II_rand[0] == NULL) {
+    // This check applies to these functions
+    static const char * const identifiers[num_rands] = {
+      "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
+      "lcong48",
+      "rand", "rand_r"
+    };
+
+    for (size_t i = 0; i < num_rands; i++)
+      II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
+  }
+
+  const IdentifierInfo *id = FD->getIdentifier();
+  size_t identifierid;
+
+  for (identifierid = 0; identifierid < num_rands; identifierid++)
+    if (id == II_rand[identifierid])
+      break;
+
+  if (identifierid >= num_rands)
+    return;
+
+  const FunctionProtoType *FTP
+    = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+  if (!FTP)
+    return;
+
+  if (FTP->getNumArgs() == 1) {
+    // Is the argument an 'unsigned short *'?
+    // (Actually any integer type is allowed.)
+    const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
+    if (!PT)
+      return;
+
+    if (! PT->getPointeeType()->isIntegerType())
+      return;
+  }
+  else if (FTP->getNumArgs() != 0)
+    return;
+
+  // Issue a warning.
+  llvm::SmallString<256> buf1;
+  llvm::raw_svector_ostream os1(buf1);
+  os1 << '\'' << FD << "' is a poor random number generator";
+
+  llvm::SmallString<256> buf2;
+  llvm::raw_svector_ostream os2(buf2);
+  os2 << "Function '" << FD
+      << "' is obsolete because it implements a poor random number generator."
+      << "  Use 'arc4random' instead";
+
+  SourceRange R = CE->getCallee()->getSourceRange();
+  BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: 'random' should not be used
+// Originally: <rdar://problem/63371000>
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
+  if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
+    return;
+
+  const FunctionProtoType *FTP
+    = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+  if (!FTP)
+    return;
+
+  // Verify that the function takes no argument.
+  if (FTP->getNumArgs() != 0)
+    return;
+
+  // Issue a warning.
+  SourceRange R = CE->getCallee()->getSourceRange();
+  BR.EmitBasicReport("'random' is not a secure random number generator",
+                     "Security",
+                     "The 'random' function produces a sequence of values that "
+                     "an adversary may be able to predict.  Use 'arc4random' "
+                     "instead", CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Check: Should check whether privileges are dropped successfully.
+// Originally: <rdar://problem/6337132>
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
+  const FunctionDecl *FD = CE->getDirectCallee();
+  if (!FD)
+    return;
+
+  if (II_setid[0] == NULL) {
+    static const char * const identifiers[num_setids] = {
+      "setuid", "setgid", "seteuid", "setegid",
+      "setreuid", "setregid"
+    };
+
+    for (size_t i = 0; i < num_setids; i++)
+      II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
+  }
+
+  const IdentifierInfo *id = FD->getIdentifier();
+  size_t identifierid;
+
+  for (identifierid = 0; identifierid < num_setids; identifierid++)
+    if (id == II_setid[identifierid])
+      break;
+
+  if (identifierid >= num_setids)
+    return;
+
+  const FunctionProtoType *FTP
+    = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
+  if (!FTP)
+    return;
+
+  // Verify that the function takes one or two arguments (depending on
+  //   the function).
+  if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
+    return;
+
+  // The arguments must be integers.
+  for (unsigned i = 0; i < FTP->getNumArgs(); i++)
+    if (! FTP->getArgType(i)->isIntegerType())
+      return;
+
+  // Issue a warning.
+  llvm::SmallString<256> buf1;
+  llvm::raw_svector_ostream os1(buf1);
+  os1 << "Return value is not checked in call to '" << FD << '\'';
+
+  llvm::SmallString<256> buf2;
+  llvm::raw_svector_ostream os2(buf2);
+  os2 << "The return value from the call to '" << FD
+      << "' is not checked.  If an error occurs in '" << FD
+      << "', the following code may execute with unexpected privileges";
+
+  SourceRange R = CE->getCallee()->getSourceRange();
+  BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
+// Entry point for check.
+//===----------------------------------------------------------------------===//
+
+void ento::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
+  WalkAST walker(BR);
+  walker.Visit(D->getBody());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp
new file mode 100644 (file)
index 0000000..ed060b2
--- /dev/null
@@ -0,0 +1,72 @@
+//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- 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 a check for unintended use of sizeof() on pointer
+//  expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class WalkAST : public StmtVisitor<WalkAST> {
+  BugReporter &BR;
+
+public:
+  WalkAST(BugReporter &br) : BR(br) {}
+  void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+  void VisitStmt(Stmt *S) { VisitChildren(S); }
+  void VisitChildren(Stmt *S);
+};
+}
+
+void WalkAST::VisitChildren(Stmt *S) {
+  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+    if (Stmt *child = *I)
+      Visit(child);
+}
+
+// CWE-467: Use of sizeof() on a Pointer Type
+void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+  if (!E->isSizeOf())
+    return;
+
+  // If an explicit type is used in the code, usually the coder knows what he is
+  // doing.
+  if (E->isArgumentType())
+    return;
+
+  QualType T = E->getTypeOfArgument();
+  if (T->isPointerType()) {
+
+    // Many false positives have the form 'sizeof *p'. This is reasonable 
+    // because people know what they are doing when they intentionally 
+    // dereference the pointer.
+    Expr *ArgEx = E->getArgumentExpr();
+    if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
+      return;
+
+    SourceRange R = ArgEx->getSourceRange();
+    BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type",
+                       "Logic",
+                       "The code calls sizeof() on a pointer type. "
+                       "This can produce an unexpected result.",
+                       E->getLocStart(), &R, 1);
+  }
+}
+
+void ento::CheckSizeofPointer(const Decl *D, BugReporter &BR) {
+  WalkAST walker(BR);
+  walker.Visit(D->getBody());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp
new file mode 100644 (file)
index 0000000..a3f4daa
--- /dev/null
@@ -0,0 +1,162 @@
+//===- Chrootchecker.cpp -------- Basic security checks ----------*- 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 chroot checker, which checks improper use of chroot.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineExperimentalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableMap.h"
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+// enum value that represent the jail state
+enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
+  
+bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
+//bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
+
+// This checker checks improper use of chroot.
+// The state transition:
+// NO_CHROOT ---chroot(path)--> ROOT_CHANGED ---chdir(/) --> JAIL_ENTERED
+//                                  |                               |
+//         ROOT_CHANGED<--chdir(..)--      JAIL_ENTERED<--chdir(..)--
+//                                  |                               |
+//                      bug<--foo()--          JAIL_ENTERED<--foo()--
+class ChrootChecker : public CheckerVisitor<ChrootChecker> {
+  IdentifierInfo *II_chroot, *II_chdir;
+  // This bug refers to possibly break out of a chroot() jail.
+  BuiltinBug *BT_BreakJail;
+
+public:
+  ChrootChecker() : II_chroot(0), II_chdir(0), BT_BreakJail(0) {}
+  
+  static void *getTag() {
+    static int x;
+    return &x;
+  }
+  
+  virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+  virtual void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+
+private:
+  void Chroot(CheckerContext &C, const CallExpr *CE);
+  void Chdir(CheckerContext &C, const CallExpr *CE);
+};
+
+} // end anonymous namespace
+
+void ento::RegisterChrootChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new ChrootChecker());
+}
+
+bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+  const FunctionDecl *FD = L.getAsFunctionDecl();
+  if (!FD)
+    return false;
+
+  ASTContext &Ctx = C.getASTContext();
+  if (!II_chroot)
+    II_chroot = &Ctx.Idents.get("chroot");
+  if (!II_chdir)
+    II_chdir = &Ctx.Idents.get("chdir");
+
+  if (FD->getIdentifier() == II_chroot) {
+    Chroot(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_chdir) {
+    Chdir(C, CE);
+    return true;
+  }
+
+  return false;
+}
+
+void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  GRStateManager &Mgr = state->getStateManager();
+  
+  // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in 
+  // the GDM.
+  state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
+  C.addTransition(state);
+}
+
+void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  GRStateManager &Mgr = state->getStateManager();
+
+  // If there are no jail state in the GDM, just return.
+  const void* k = state->FindGDM(ChrootChecker::getTag());
+  if (!k)
+    return;
+
+  // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
+  const Expr *ArgExpr = CE->getArg(0);
+  SVal ArgVal = state->getSVal(ArgExpr);
+  
+  if (const MemRegion *R = ArgVal.getAsRegion()) {
+    R = R->StripCasts();
+    if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
+      const StringLiteral* Str = StrRegion->getStringLiteral();
+      if (Str->getString() == "/")
+        state = Mgr.addGDM(state, ChrootChecker::getTag(),
+                           (void*) JAIL_ENTERED);
+    }
+  }
+
+  C.addTransition(state);
+}
+
+// Check the jail state before any function call except chroot and chdir().
+void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+  const FunctionDecl *FD = L.getAsFunctionDecl();
+  if (!FD)
+    return;
+
+  ASTContext &Ctx = C.getASTContext();
+  if (!II_chroot)
+    II_chroot = &Ctx.Idents.get("chroot");
+  if (!II_chdir)
+    II_chdir = &Ctx.Idents.get("chdir");
+
+  // Ingnore chroot and chdir.
+  if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
+    return;
+  
+  // If jail state is ROOT_CHANGED, generate BugReport.
+  void* const* k = state->FindGDM(ChrootChecker::getTag());
+  if (k)
+    if (isRootChanged((intptr_t) *k))
+      if (ExplodedNode *N = C.generateNode()) {
+        if (!BT_BreakJail)
+          BT_BreakJail = new BuiltinBug("Break out of jail",
+                                        "No call of chdir(\"/\") immediately "
+                                        "after chroot");
+        BugReport *R = new BugReport(*BT_BreakJail, 
+                                     BT_BreakJail->getDescription(), N);
+        C.EmitReport(R);
+      }
+  
+  return;
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp
new file mode 100644 (file)
index 0000000..7dc8ec8
--- /dev/null
@@ -0,0 +1,204 @@
+//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NullDerefChecker, a builtin check in ExprEngine that performs
+// checks for null pointers at loads and stores.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class DereferenceChecker : public Checker {
+  BuiltinBug *BT_null;
+  BuiltinBug *BT_undef;
+  llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
+public:
+  DereferenceChecker() : BT_null(0), BT_undef(0) {}
+  static void *getTag() { static int tag = 0; return &tag; }
+  void visitLocation(CheckerContext &C, const Stmt *S, SVal location);
+
+  std::pair<ExplodedNode * const*, ExplodedNode * const*>
+  getImplicitNodes() const {
+    return std::make_pair(ImplicitNullDerefNodes.data(),
+                          ImplicitNullDerefNodes.data() +
+                          ImplicitNullDerefNodes.size());
+  }
+  void AddDerefSource(llvm::raw_ostream &os,
+                      llvm::SmallVectorImpl<SourceRange> &Ranges,
+                      const Expr *Ex, bool loadedFrom = false);
+};
+} // end anonymous namespace
+
+void ento::RegisterDereferenceChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new DereferenceChecker());
+}
+
+std::pair<ExplodedNode * const *, ExplodedNode * const *>
+ento::GetImplicitNullDereferences(ExprEngine &Eng) {
+  DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
+  if (!checker)
+    return std::make_pair((ExplodedNode * const *) 0,
+                          (ExplodedNode * const *) 0);
+  return checker->getImplicitNodes();
+}
+
+void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
+                                     llvm::SmallVectorImpl<SourceRange> &Ranges,
+                                        const Expr *Ex,
+                                        bool loadedFrom) {
+  Ex = Ex->IgnoreParenLValueCasts();
+  switch (Ex->getStmtClass()) {
+    default:
+      return;
+    case Stmt::DeclRefExprClass: {
+      const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
+      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+        os << " (" << (loadedFrom ? "loaded from" : "from")
+           << " variable '" <<  VD->getName() << "')";
+        Ranges.push_back(DR->getSourceRange());
+      }
+      return;
+    }
+    case Stmt::MemberExprClass: {
+      const MemberExpr *ME = cast<MemberExpr>(Ex);
+      os << " (" << (loadedFrom ? "loaded from" : "via")
+         << " field '" << ME->getMemberNameInfo() << "')";
+      SourceLocation L = ME->getMemberLoc();
+      Ranges.push_back(SourceRange(L, L));
+      break;
+    }
+  }
+}
+
+void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
+                                       SVal l) {
+  // Check for dereference of an undefined value.
+  if (l.isUndef()) {
+    if (ExplodedNode *N = C.generateSink()) {
+      if (!BT_undef)
+        BT_undef = new BuiltinBug("Dereference of undefined pointer value");
+
+      EnhancedBugReport *report =
+        new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
+      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                                bugreporter::GetDerefExpr(N));
+      C.EmitReport(report);
+    }
+    return;
+  }
+
+  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
+
+  // Check for null dereferences.
+  if (!isa<Loc>(location))
+    return;
+
+  const GRState *state = C.getState();
+  const GRState *notNullState, *nullState;
+  llvm::tie(notNullState, nullState) = state->assume(location);
+
+  // The explicit NULL case.
+  if (nullState) {
+    if (!notNullState) {
+      // Generate an error node.
+      ExplodedNode *N = C.generateSink(nullState);
+      if (!N)
+        return;
+
+      // We know that 'location' cannot be non-null.  This is what
+      // we call an "explicit" null dereference.
+      if (!BT_null)
+        BT_null = new BuiltinBug("Dereference of null pointer");
+
+      llvm::SmallString<100> buf;
+      llvm::SmallVector<SourceRange, 2> Ranges;
+      
+      // Walk through lvalue casts to get the original expression
+      // that syntactically caused the load.
+      if (const Expr *expr = dyn_cast<Expr>(S))
+        S = expr->IgnoreParenLValueCasts();
+
+      switch (S->getStmtClass()) {
+        case Stmt::ArraySubscriptExprClass: {
+          llvm::raw_svector_ostream os(buf);
+          os << "Array access";
+          const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
+          AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts());
+          os << " results in a null pointer dereference";
+          break;
+        }
+        case Stmt::UnaryOperatorClass: {
+          llvm::raw_svector_ostream os(buf);
+          os << "Dereference of null pointer";
+          const UnaryOperator *U = cast<UnaryOperator>(S);
+          AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true);
+          break;
+        }
+        case Stmt::MemberExprClass: {
+          const MemberExpr *M = cast<MemberExpr>(S);
+          if (M->isArrow()) {
+            llvm::raw_svector_ostream os(buf);
+            os << "Access to field '" << M->getMemberNameInfo()
+               << "' results in a dereference of a null pointer";
+            AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true);
+          }
+          break;
+        }
+        case Stmt::ObjCIvarRefExprClass: {
+          const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
+          if (const DeclRefExpr *DR =
+              dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
+            if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+              llvm::raw_svector_ostream os(buf);
+              os << "Instance variable access (via '" << VD->getName()
+                 << "') results in a null pointer dereference";
+            }
+          }
+          Ranges.push_back(IV->getSourceRange());
+          break;
+        }
+        default:
+          break;
+      }
+
+      EnhancedBugReport *report =
+        new EnhancedBugReport(*BT_null,
+                              buf.empty() ? BT_null->getDescription():buf.str(),
+                              N);
+
+      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                                bugreporter::GetDerefExpr(N));
+
+      for (llvm::SmallVectorImpl<SourceRange>::iterator
+            I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
+        report->addRange(*I);
+
+      C.EmitReport(report);
+      return;
+    }
+    else {
+      // Otherwise, we have the case where the location could either be
+      // null or not-null.  Record the error node as an "implicit" null
+      // dereference.
+      if (ExplodedNode *N = C.generateSink(nullState))
+        ImplicitNullDerefNodes.push_back(N);
+    }
+  }
+
+  // From this point forward, we know that the location is not null.
+  C.addTransition(notNullState);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp
new file mode 100644 (file)
index 0000000..8332af8
--- /dev/null
@@ -0,0 +1,86 @@
+//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines DivZeroChecker, a builtin check in ExprEngine that performs
+// checks for division by zeros.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
+  BuiltinBug *BT;
+public:
+  DivZeroChecker() : BT(0) {}  
+  static void *getTag();
+  void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};  
+} // end anonymous namespace
+
+void ento::RegisterDivZeroChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new DivZeroChecker());
+}
+
+void *DivZeroChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
+                                            const BinaryOperator *B) {
+  BinaryOperator::Opcode Op = B->getOpcode();
+  if (Op != BO_Div &&
+      Op != BO_Rem &&
+      Op != BO_DivAssign &&
+      Op != BO_RemAssign)
+    return;
+
+  if (!B->getRHS()->getType()->isIntegerType() ||
+      !B->getRHS()->getType()->isScalarType())
+    return;
+
+  SVal Denom = C.getState()->getSVal(B->getRHS());
+  const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
+
+  // Divide-by-undefined handled in the generic checking for uses of
+  // undefined values.
+  if (!DV)
+    return;
+
+  // Check for divide by zero.
+  ConstraintManager &CM = C.getConstraintManager();
+  const GRState *stateNotZero, *stateZero;
+  llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
+
+  if (stateZero && !stateNotZero) {
+    if (ExplodedNode *N = C.generateSink(stateZero)) {
+      if (!BT)
+        BT = new BuiltinBug("Division by zero");
+
+      EnhancedBugReport *R = 
+        new EnhancedBugReport(*BT, BT->getDescription(), N);
+
+      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                           bugreporter::GetDenomExpr(N));
+
+      C.EmitReport(R);
+    }
+    return;
+  }
+
+  // If we get here, then the denom should not be zero. We abandon the implicit
+  // zero denom case for now.
+  C.addTransition(stateNotZero);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp
new file mode 100644 (file)
index 0000000..17bc339
--- /dev/null
@@ -0,0 +1,3513 @@
+//=-- ExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
+//  is built on GREngine, but provides the boilerplate to execute transfer
+//  functions and build the ExplodedGraph at the expression level.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Restructure checker registration.
+#include "ExprEngineInternalChecks.h"
+
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/ImmutableList.h"
+
+#ifndef NDEBUG
+#include "llvm/Support/GraphWriter.h"
+#endif
+
+using namespace clang;
+using namespace ento;
+using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
+using llvm::cast;
+using llvm::APSInt;
+
+namespace {
+  // Trait class for recording returned expression in the state.
+  struct ReturnExpr {
+    static int TagInt;
+    typedef const Stmt *data_type;
+  };
+  int ReturnExpr::TagInt; 
+}
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+  IdentifierInfo* II = &Ctx.Idents.get(name);
+  return Ctx.Selectors.getSelector(0, &II);
+}
+
+//===----------------------------------------------------------------------===//
+// Checker worklist routines.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
+                                ExplodedNodeSet &Src, CallbackKind Kind) {
+
+  // Determine if we already have a cached 'CheckersOrdered' vector
+  // specifically tailored for the provided <CallbackKind, Stmt kind>.  This
+  // can reduce the number of checkers actually called.
+  CheckersOrdered *CO = &Checkers;
+  llvm::OwningPtr<CheckersOrdered> NewCO;
+
+  // The cache key is made up of the and the callback kind (pre- or post-visit)
+  // and the statement kind.
+  CallbackTag K = GetCallbackTag(Kind, S->getStmtClass());
+
+  CheckersOrdered *& CO_Ref = COCache[K];
+  
+  if (!CO_Ref) {
+    // If we have no previously cached CheckersOrdered vector for this
+    // statement kind, then create one.
+    NewCO.reset(new CheckersOrdered);
+  }
+  else {
+    // Use the already cached set.
+    CO = CO_Ref;
+  }
+  
+  if (CO->empty()) {
+    // If there are no checkers, return early without doing any
+    // more work.
+    Dst.insert(Src);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  ExplodedNodeSet *PrevSet = &Src;
+  unsigned checkersEvaluated = 0;
+
+  for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) {
+    // If all nodes are sunk, bail out early.
+    if (PrevSet->empty())
+      break;
+    ExplodedNodeSet *CurrSet = 0;
+    if (I+1 == E)
+      CurrSet = &Dst;
+    else {
+      CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+      CurrSet->clear();
+    }
+    void *tag = I->first;
+    Checker *checker = I->second;
+    bool respondsToCallback = true;
+
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI) {
+
+      checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag,
+                        Kind == PreVisitStmtCallback, respondsToCallback);
+      
+    }
+
+    PrevSet = CurrSet;
+
+    if (NewCO.get()) {
+      ++checkersEvaluated;
+      if (respondsToCallback)
+        NewCO->push_back(*I);
+    }    
+  }
+  
+  // If we built NewCO, check if we called all the checkers.  This is important
+  // so that we know that we accurately determined the entire set of checkers
+  // that responds to this callback.  Note that 'checkersEvaluated' might
+  // not be the same as Checkers.size() if one of the Checkers generates
+  // a sink node.
+  if (NewCO.get() && checkersEvaluated == Checkers.size())
+    CO_Ref = NewCO.take();
+
+  // Don't autotransition.  The CheckerContext objects should do this
+  // automatically.
+}
+
+void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+                                          ExplodedNodeSet &Dst,
+                                          const GRState *state,
+                                          ExplodedNode *Pred) {
+  bool evaluated = false;
+  ExplodedNodeSet DstTmp;
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
+                                    tag)) {
+      evaluated = true;
+      break;
+    } else
+      // The checker didn't evaluate the expr. Restore the Dst.
+      DstTmp.clear();
+  }
+
+  if (evaluated)
+    Dst.insert(DstTmp);
+  else
+    Dst.insert(Pred);
+}
+
+// CheckerEvalCall returns true if one of the checkers processed the node.
+// This may return void when all call evaluation logic goes to some checker
+// in the future.
+bool ExprEngine::CheckerEvalCall(const CallExpr *CE,
+                                   ExplodedNodeSet &Dst,
+                                   ExplodedNode *Pred) {
+  bool evaluated = false;
+  ExplodedNodeSet DstTmp;
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) {
+      evaluated = true;
+      break;
+    } else
+      // The checker didn't evaluate the expr. Restore the DstTmp set.
+      DstTmp.clear();
+  }
+
+  if (evaluated)
+    Dst.insert(DstTmp);
+  else
+    Dst.insert(Pred);
+
+  return evaluated;
+}
+
+// FIXME: This is largely copy-paste from CheckerVisit().  Need to
+// unify.
+void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
+                                    ExplodedNodeSet &Src, SVal location,
+                                    SVal val, bool isPrevisit) {
+
+  if (Checkers.empty()) {
+    Dst.insert(Src);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  ExplodedNodeSet *PrevSet = &Src;
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+  {
+    ExplodedNodeSet *CurrSet = 0;
+    if (I+1 == E)
+      CurrSet = &Dst;
+    else {
+      CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+      CurrSet->clear();
+    }
+
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI)
+      checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE,
+                            *NI, tag, location, val, isPrevisit);
+
+    // Update which NodeSet is the current one.
+    PrevSet = CurrSet;
+  }
+
+  // Don't autotransition.  The CheckerContext objects should do this
+  // automatically.
+}
+//===----------------------------------------------------------------------===//
+// Engine construction and deletion.
+//===----------------------------------------------------------------------===//
+
+static void RegisterInternalChecks(ExprEngine &Eng) {
+  // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
+  // are different than what probably many checks will do since they don't
+  // create BugReports on-the-fly but instead wait until ExprEngine finishes
+  // analyzing a function.  Generation of BugReport objects is done via a call
+  // to 'FlushReports' from BugReporter.
+  // The following checks do not need to have their associated BugTypes
+  // explicitly registered with the BugReporter.  If they issue any BugReports,
+  // their associated BugType will get registered with the BugReporter
+  // automatically.  Note that the check itself is owned by the ExprEngine
+  // object.
+  RegisterAdjustedReturnValueChecker(Eng);
+  // CallAndMessageChecker should be registered before AttrNonNullChecker,
+  // where we assume arguments are not undefined.
+  RegisterCallAndMessageChecker(Eng);
+  RegisterAttrNonNullChecker(Eng);
+  RegisterDereferenceChecker(Eng);
+  RegisterVLASizeChecker(Eng);
+  RegisterDivZeroChecker(Eng);
+  RegisterReturnUndefChecker(Eng);
+  RegisterUndefinedArraySubscriptChecker(Eng);
+  RegisterUndefinedAssignmentChecker(Eng);
+  RegisterUndefBranchChecker(Eng);
+  RegisterUndefCapturedBlockVarChecker(Eng);
+  RegisterUndefResultChecker(Eng);
+  RegisterStackAddrLeakChecker(Eng);
+  RegisterObjCAtSyncChecker(Eng);
+
+  // This is not a checker yet.
+  RegisterNoReturnFunctionChecker(Eng);
+  RegisterBuiltinFunctionChecker(Eng);
+  RegisterOSAtomicChecker(Eng);
+  RegisterUnixAPIChecker(Eng);
+  RegisterMacOSXAPIChecker(Eng);
+}
+
+ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
+  : AMgr(mgr),
+    Engine(*this),
+    G(Engine.getGraph()),
+    Builder(NULL),
+    StateMgr(getContext(), mgr.getStoreManagerCreator(),
+             mgr.getConstraintManagerCreator(), G.getAllocator(),
+             *this),
+    SymMgr(StateMgr.getSymbolManager()),
+    svalBuilder(StateMgr.getSValBuilder()),
+    EntryNode(NULL), currentStmt(NULL),
+    NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
+    RaiseSel(GetNullarySelector("raise", getContext())),
+    BR(mgr, *this), TF(tf) {
+  // Register internal checks.
+  RegisterInternalChecks(*this);
+
+  // FIXME: Eventually remove the TF object entirely.
+  TF->RegisterChecks(*this);
+  TF->RegisterPrinters(getStateManager().Printers);
+}
+
+ExprEngine::~ExprEngine() {
+  BR.FlushReports();
+  delete [] NSExceptionInstanceRaiseSelectors;
+  
+  // Delete the set of checkers.
+  for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
+    delete I->second;
+  
+  for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end();
+       I!=E;++I)
+    delete I->second;
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods.
+//===----------------------------------------------------------------------===//
+
+const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
+  const GRState *state = StateMgr.getInitialState(InitLoc);
+
+  // Preconditions.
+
+  // FIXME: It would be nice if we had a more general mechanism to add
+  // such preconditions.  Some day.
+  do {
+    const Decl *D = InitLoc->getDecl();
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+      // Precondition: the first argument of 'main' is an integer guaranteed
+      //  to be > 0.
+      const IdentifierInfo *II = FD->getIdentifier();
+      if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
+        break;
+
+      const ParmVarDecl *PD = FD->getParamDecl(0);
+      QualType T = PD->getType();
+      if (!T->isIntegerType())
+        break;
+
+      const MemRegion *R = state->getRegion(PD, InitLoc);
+      if (!R)
+        break;
+
+      SVal V = state->getSVal(loc::MemRegionVal(R));
+      SVal Constraint_untested = evalBinOp(state, BO_GT, V,
+                                           svalBuilder.makeZeroVal(T),
+                                           getContext().IntTy);
+
+      DefinedOrUnknownSVal *Constraint =
+        dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
+
+      if (!Constraint)
+        break;
+
+      if (const GRState *newState = state->assume(*Constraint, true))
+        state = newState;
+
+      break;
+    }
+
+    if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+      // Precondition: 'self' is always non-null upon entry to an Objective-C
+      // method.
+      const ImplicitParamDecl *SelfD = MD->getSelfDecl();
+      const MemRegion *R = state->getRegion(SelfD, InitLoc);
+      SVal V = state->getSVal(loc::MemRegionVal(R));
+
+      if (const Loc *LV = dyn_cast<Loc>(&V)) {
+        // Assume that the pointer value in 'self' is non-null.
+        state = state->assume(*LV, true);
+        assert(state && "'self' cannot be null");
+      }
+    }
+  } while (0);
+
+  return state;
+}
+
+//===----------------------------------------------------------------------===//
+// Top-level transfer function logic (Dispatcher).
+//===----------------------------------------------------------------------===//
+
+/// evalAssume - Called by ConstraintManager. Used to call checker-specific
+///  logic for handling assumptions on symbolic values.
+const GRState *ExprEngine::ProcessAssume(const GRState *state, SVal cond,
+                                           bool assumption) {
+  // Determine if we already have a cached 'CheckersOrdered' vector
+  // specifically tailored for processing assumptions.  This
+  // can reduce the number of checkers actually called.
+  CheckersOrdered *CO = &Checkers;
+  llvm::OwningPtr<CheckersOrdered> NewCO;
+
+  CallbackTag K = GetCallbackTag(ProcessAssumeCallback);
+  CheckersOrdered *& CO_Ref = COCache[K];
+
+  if (!CO_Ref) {
+    // If we have no previously cached CheckersOrdered vector for this
+    // statement kind, then create one.
+    NewCO.reset(new CheckersOrdered);
+  }
+  else {
+    // Use the already cached set.
+    CO = CO_Ref;
+  }
+
+  if (!CO->empty()) {
+    // Let the checkers have a crack at the assume before the transfer functions
+    // get their turn.
+    for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) {
+
+      // If any checker declares the state infeasible (or if it starts that
+      // way), bail out.
+      if (!state)
+        return NULL;
+
+      Checker *C = I->second;
+      bool respondsToCallback = true;
+
+      state = C->evalAssume(state, cond, assumption, &respondsToCallback);
+
+      // Check if we're building the cache of checkers that care about
+      // assumptions.
+      if (NewCO.get() && respondsToCallback)
+        NewCO->push_back(*I);
+    }
+
+    // If we got through all the checkers, and we built a list of those that
+    // care about assumptions, save it.
+    if (NewCO.get())
+      CO_Ref = NewCO.take();
+  }
+
+  // If the state is infeasible at this point, bail out.
+  if (!state)
+    return NULL;
+
+  return TF->evalAssume(state, cond, assumption);
+}
+
+bool ExprEngine::WantsRegionChangeUpdate(const GRState* state) {
+  CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
+  CheckersOrdered *CO = COCache[K];
+
+  if (!CO)
+    CO = &Checkers;
+
+  for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
+    Checker *C = I->second;
+    if (C->WantsRegionChangeUpdate(state))
+      return true;
+  }
+
+  return false;
+}
+
+const GRState *
+ExprEngine::ProcessRegionChanges(const GRState *state,
+                                   const MemRegion * const *Begin,
+                                   const MemRegion * const *End) {
+  // FIXME: Most of this method is copy-pasted from ProcessAssume.
+
+  // Determine if we already have a cached 'CheckersOrdered' vector
+  // specifically tailored for processing region changes.  This
+  // can reduce the number of checkers actually called.
+  CheckersOrdered *CO = &Checkers;
+  llvm::OwningPtr<CheckersOrdered> NewCO;
+
+  CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
+  CheckersOrdered *& CO_Ref = COCache[K];
+
+  if (!CO_Ref) {
+    // If we have no previously cached CheckersOrdered vector for this
+    // callback, then create one.
+    NewCO.reset(new CheckersOrdered);
+  }
+  else {
+    // Use the already cached set.
+    CO = CO_Ref;
+  }
+
+  // If there are no checkers, just return the state as is.
+  if (CO->empty())
+    return state;
+
+  for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
+    // If any checker declares the state infeasible (or if it starts that way),
+    // bail out.
+    if (!state)
+      return NULL;
+
+    Checker *C = I->second;
+    bool respondsToCallback = true;
+
+    state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback);
+
+    // See if we're building a cache of checkers that care about region changes.
+    if (NewCO.get() && respondsToCallback)
+      NewCO->push_back(*I);
+  }
+
+  // If we got through all the checkers, and we built a list of those that
+  // care about region changes, save it.
+  if (NewCO.get())
+    CO_Ref = NewCO.take();
+
+  return state;
+}
+
+void ExprEngine::ProcessEndWorklist(bool hasWorkRemaining) {
+  for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+       I != E; ++I) {
+    I->second->VisitEndAnalysis(G, BR, *this);
+  }
+}
+
+void ExprEngine::ProcessElement(const CFGElement E, 
+                                  StmtNodeBuilder& builder) {
+  switch (E.getKind()) {
+  case CFGElement::Statement:
+    ProcessStmt(E.getAs<CFGStmt>(), builder);
+    break;
+  case CFGElement::Initializer:
+    ProcessInitializer(E.getAs<CFGInitializer>(), builder);
+    break;
+  case CFGElement::ImplicitDtor:
+    ProcessImplicitDtor(E.getAs<CFGImplicitDtor>(), builder);
+    break;
+  default:
+    // Suppress compiler warning.
+    llvm_unreachable("Unexpected CFGElement kind.");
+  }
+}
+
+void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
+  currentStmt = S.getStmt();
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+                                currentStmt->getLocStart(),
+                                "Error evaluating statement");
+
+  Builder = &builder;
+  EntryNode = builder.getBasePredecessor();
+
+  // Create the cleaned state.
+  const LocationContext *LC = EntryNode->getLocationContext();
+  SymbolReaper SymReaper(LC, currentStmt, SymMgr);
+
+  if (AMgr.shouldPurgeDead()) {
+    const GRState *St = EntryNode->getState();
+
+    for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+         I != E; ++I) {
+      Checker *checker = I->second;
+      checker->MarkLiveSymbols(St, SymReaper);
+    }
+
+    const StackFrameContext *SFC = LC->getCurrentStackFrame();
+    CleanedState = StateMgr.RemoveDeadBindings(St, SFC, SymReaper);
+  } else {
+    CleanedState = EntryNode->getState();
+  }
+
+  // Process any special transfer function for dead symbols.
+  ExplodedNodeSet Tmp;
+
+  if (!SymReaper.hasDeadSymbols())
+    Tmp.Add(EntryNode);
+  else {
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+    SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
+    Builder->PurgingDeadSymbols = true;
+
+    // FIXME: This should soon be removed.
+    ExplodedNodeSet Tmp2;
+    getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
+                            CleanedState, SymReaper);
+
+    if (Checkers.empty())
+      Tmp.insert(Tmp2);
+    else {
+      ExplodedNodeSet Tmp3;
+      ExplodedNodeSet *SrcSet = &Tmp2;
+      for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+           I != E; ++I) {
+        ExplodedNodeSet *DstSet = 0;
+        if (I+1 == E)
+          DstSet = &Tmp;
+        else {
+          DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
+          DstSet->clear();
+        }
+
+        void *tag = I->first;
+        Checker *checker = I->second;
+        for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
+             NI != NE; ++NI)
+          checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt,
+                                      *NI, SymReaper, tag);
+        SrcSet = DstSet;
+      }
+    }
+
+    if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
+      Tmp.Add(EntryNode);
+  }
+
+  bool HasAutoGenerated = false;
+
+  for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+    ExplodedNodeSet Dst;
+
+    // Set the cleaned state.
+    Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
+
+    // Visit the statement.
+    Visit(currentStmt, *I, Dst);
+
+    // Do we need to auto-generate a node?  We only need to do this to generate
+    // a node with a "cleaned" state; CoreEngine will actually handle
+    // auto-transitions for other cases.
+    if (Dst.size() == 1 && *Dst.begin() == EntryNode
+        && !Builder->HasGeneratedNode && !HasAutoGenerated) {
+      HasAutoGenerated = true;
+      builder.generateNode(currentStmt, GetState(EntryNode), *I);
+    }
+  }
+
+  // NULL out these variables to cleanup.
+  CleanedState = NULL;
+  EntryNode = NULL;
+
+  currentStmt = 0;
+
+  Builder = NULL;
+}
+
+void ExprEngine::ProcessInitializer(const CFGInitializer Init,
+                                    StmtNodeBuilder &builder) {
+  // We don't set EntryNode and currentStmt. And we don't clean up state.
+  const CXXBaseOrMemberInitializer *BMI = Init.getInitializer();
+
+  ExplodedNode *Pred = builder.getBasePredecessor();
+  const LocationContext *LC = Pred->getLocationContext();
+
+  if (BMI->isAnyMemberInitializer()) {
+    ExplodedNodeSet Dst;
+
+    // Evaluate the initializer.
+    Visit(BMI->getInit(), Pred, Dst);
+
+    for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){
+      ExplodedNode *Pred = *I;
+      const GRState *state = Pred->getState();
+
+      const FieldDecl *FD = BMI->getAnyMember();
+      const RecordDecl *RD = FD->getParent();
+      const CXXThisRegion *ThisR = getCXXThisRegion(cast<CXXRecordDecl>(RD),
+                           cast<StackFrameContext>(LC));
+
+      SVal ThisV = state->getSVal(ThisR);
+      SVal FieldLoc = state->getLValue(FD, ThisV);
+      SVal InitVal = state->getSVal(BMI->getInit());
+      state = state->bindLoc(FieldLoc, InitVal);
+
+      // Use a custom node building process.
+      PostInitializer PP(BMI, LC);
+      // Builder automatically add the generated node to the deferred set,
+      // which are processed in the builder's dtor.
+      builder.generateNode(PP, state, Pred);
+    }
+  }
+}
+
+void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
+                                       StmtNodeBuilder &builder) {
+  Builder = &builder;
+
+  switch (D.getDtorKind()) {
+  case CFGElement::AutomaticObjectDtor:
+    ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), builder);
+    break;
+  case CFGElement::BaseDtor:
+    ProcessBaseDtor(cast<CFGBaseDtor>(D), builder);
+    break;
+  case CFGElement::MemberDtor:
+    ProcessMemberDtor(cast<CFGMemberDtor>(D), builder);
+    break;
+  case CFGElement::TemporaryDtor:
+    ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), builder);
+    break;
+  default:
+    llvm_unreachable("Unexpected dtor kind.");
+  }
+}
+
+void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
+                                           StmtNodeBuilder &builder) {
+  ExplodedNode *pred = builder.getBasePredecessor();
+  const GRState *state = pred->getState();
+  const VarDecl *varDecl = dtor.getVarDecl();
+
+  QualType varType = varDecl->getType();
+
+  if (const ReferenceType *refType = varType->getAs<ReferenceType>())
+    varType = refType->getPointeeType();
+
+  const CXXRecordDecl *recordDecl = varType->getAsCXXRecordDecl();
+  assert(recordDecl && "get CXXRecordDecl fail");
+  const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor();
+
+  Loc dest = state->getLValue(varDecl, pred->getLocationContext());
+
+  ExplodedNodeSet dstSet;
+  VisitCXXDestructor(dtorDecl, cast<loc::MemRegionVal>(dest).getRegion(),
+                     dtor.getTriggerStmt(), pred, dstSet);
+}
+
+void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
+                                   StmtNodeBuilder &builder) {
+}
+
+void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
+                                     StmtNodeBuilder &builder) {
+}
+
+void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
+                                        StmtNodeBuilder &builder) {
+}
+
+void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, 
+                         ExplodedNodeSet& Dst) {
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+                                S->getLocStart(),
+                                "Error evaluating statement");
+
+  // Expressions to ignore.
+  if (const Expr *Ex = dyn_cast<Expr>(S))
+    S = Ex->IgnoreParens();
+  
+  // FIXME: add metadata to the CFG so that we can disable
+  //  this check when we KNOW that there is no block-level subexpression.
+  //  The motivation is that this check requires a hashtable lookup.
+
+  if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) {
+    Dst.Add(Pred);
+    return;
+  }
+
+  switch (S->getStmtClass()) {
+    // C++ stuff we don't support yet.
+    case Stmt::CXXBindTemporaryExprClass:
+    case Stmt::CXXCatchStmtClass:
+    case Stmt::CXXDefaultArgExprClass:
+    case Stmt::CXXDependentScopeMemberExprClass:
+    case Stmt::ExprWithCleanupsClass:
+    case Stmt::CXXNullPtrLiteralExprClass:
+    case Stmt::CXXPseudoDestructorExprClass:
+    case Stmt::CXXTemporaryObjectExprClass:
+    case Stmt::CXXThrowExprClass:
+    case Stmt::CXXTryStmtClass:
+    case Stmt::CXXTypeidExprClass:
+    case Stmt::CXXUuidofExprClass:
+    case Stmt::CXXUnresolvedConstructExprClass:
+    case Stmt::CXXScalarValueInitExprClass:
+    case Stmt::DependentScopeDeclRefExprClass:
+    case Stmt::UnaryTypeTraitExprClass:
+    case Stmt::BinaryTypeTraitExprClass:
+    case Stmt::UnresolvedLookupExprClass:
+    case Stmt::UnresolvedMemberExprClass:
+    case Stmt::CXXNoexceptExprClass:
+    {
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      Builder->BuildSinks = true;
+      MakeNode(Dst, S, Pred, GetState(Pred));
+      break;
+    }
+      
+    case Stmt::ParenExprClass:
+      llvm_unreachable("ParenExprs already handled.");
+    // Cases that should never be evaluated simply because they shouldn't
+    // appear in the CFG.
+    case Stmt::BreakStmtClass:
+    case Stmt::CaseStmtClass:
+    case Stmt::CompoundStmtClass:
+    case Stmt::ContinueStmtClass:
+    case Stmt::DefaultStmtClass:
+    case Stmt::DoStmtClass:
+    case Stmt::GotoStmtClass:
+    case Stmt::IndirectGotoStmtClass:
+    case Stmt::LabelStmtClass:
+    case Stmt::NoStmtClass:
+    case Stmt::NullStmtClass:
+    case Stmt::SwitchCaseClass:
+    case Stmt::OpaqueValueExprClass:
+      llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+      break;
+
+    case Stmt::GNUNullExprClass: {
+      MakeNode(Dst, S, Pred, GetState(Pred)->BindExpr(S, svalBuilder.makeNull()));
+      break;
+    }
+
+    case Stmt::ObjCAtSynchronizedStmtClass:
+      VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
+      break;
+
+    // Cases not handled yet; but will handle some day.
+    case Stmt::DesignatedInitExprClass:
+    case Stmt::ExtVectorElementExprClass:
+    case Stmt::ImaginaryLiteralClass:
+    case Stmt::ImplicitValueInitExprClass:
+    case Stmt::ObjCAtCatchStmtClass:
+    case Stmt::ObjCAtFinallyStmtClass:
+    case Stmt::ObjCAtTryStmtClass:
+    case Stmt::ObjCEncodeExprClass:
+    case Stmt::ObjCIsaExprClass:
+    case Stmt::ObjCPropertyRefExprClass:
+    case Stmt::ObjCProtocolExprClass:
+    case Stmt::ObjCSelectorExprClass:
+    case Stmt::ObjCStringLiteralClass:
+    case Stmt::ParenListExprClass:
+    case Stmt::PredefinedExprClass:
+    case Stmt::ShuffleVectorExprClass:
+    case Stmt::VAArgExprClass:
+        // Fall through.
+
+    // Cases we intentionally don't evaluate, since they don't need
+    // to be explicitly evaluated.
+    case Stmt::AddrLabelExprClass:
+    case Stmt::IntegerLiteralClass:
+    case Stmt::CharacterLiteralClass:
+    case Stmt::CXXBoolLiteralExprClass:
+    case Stmt::FloatingLiteralClass:
+      Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
+      break;
+
+    case Stmt::ArraySubscriptExprClass:
+      VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::AsmStmtClass:
+      VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+      break;
+
+    case Stmt::BlockDeclRefExprClass: {
+      const BlockDeclRefExpr *BE = cast<BlockDeclRefExpr>(S);
+      VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst);
+      break;
+    }
+
+    case Stmt::BlockExprClass:
+      VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::BinaryOperatorClass: {
+      const BinaryOperator* B = cast<BinaryOperator>(S);
+      if (B->isLogicalOp()) {
+        VisitLogicalExpr(B, Pred, Dst);
+        break;
+      }
+      else if (B->getOpcode() == BO_Comma) {
+        const GRState* state = GetState(Pred);
+        MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
+        break;
+      }
+
+      if (AMgr.shouldEagerlyAssume() &&
+          (B->isRelationalOp() || B->isEqualityOp())) {
+        ExplodedNodeSet Tmp;
+        VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
+        evalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
+      }
+      else
+        VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+
+      break;
+    }
+
+    case Stmt::CallExprClass: {
+      const CallExpr* C = cast<CallExpr>(S);
+      VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
+      break;
+    }
+
+    case Stmt::CXXConstructExprClass: {
+      const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
+      // For block-level CXXConstructExpr, we don't have a destination region.
+      // Let VisitCXXConstructExpr() create one.
+      VisitCXXConstructExpr(C, 0, Pred, Dst);
+      break;
+    }
+
+    case Stmt::CXXMemberCallExprClass: {
+      const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
+      VisitCXXMemberCallExpr(MCE, Pred, Dst);
+      break;
+    }
+
+    case Stmt::CXXOperatorCallExprClass: {
+      const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S);
+      VisitCXXOperatorCallExpr(C, Pred, Dst);
+      break;
+    }
+
+    case Stmt::CXXNewExprClass: {
+      const CXXNewExpr *NE = cast<CXXNewExpr>(S);
+      VisitCXXNewExpr(NE, Pred, Dst);
+      break;
+    }
+
+    case Stmt::CXXDeleteExprClass: {
+      const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
+      VisitCXXDeleteExpr(CDE, Pred, Dst);
+      break;
+    }
+      // FIXME: ChooseExpr is really a constant.  We need to fix
+      //        the CFG do not model them as explicit control-flow.
+
+    case Stmt::ChooseExprClass: { // __builtin_choose_expr
+      const ChooseExpr* C = cast<ChooseExpr>(S);
+      VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+      break;
+    }
+
+    case Stmt::CompoundAssignOperatorClass:
+      VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+      break;
+
+    case Stmt::CompoundLiteralExprClass:
+      VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::ConditionalOperatorClass: { // '?' operator
+      const ConditionalOperator* C = cast<ConditionalOperator>(S);
+      VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+      break;
+    }
+
+    case Stmt::CXXThisExprClass:
+      VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::DeclRefExprClass: {
+      const DeclRefExpr *DE = cast<DeclRefExpr>(S);
+      VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
+      break;
+    }
+
+    case Stmt::DeclStmtClass:
+      VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
+      break;
+
+    case Stmt::ForStmtClass:
+      // This case isn't for branch processing, but for handling the
+      // initialization of a condition variable.
+      VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
+      break;
+
+    case Stmt::ImplicitCastExprClass:
+    case Stmt::CStyleCastExprClass:
+    case Stmt::CXXStaticCastExprClass:
+    case Stmt::CXXDynamicCastExprClass:
+    case Stmt::CXXReinterpretCastExprClass:
+    case Stmt::CXXConstCastExprClass:
+    case Stmt::CXXFunctionalCastExprClass: {
+      const CastExpr* C = cast<CastExpr>(S);
+      VisitCast(C, C->getSubExpr(), Pred, Dst);
+      break;
+    }
+
+    case Stmt::IfStmtClass:
+      // This case isn't for branch processing, but for handling the
+      // initialization of a condition variable.
+      VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst);
+      break;
+
+    case Stmt::InitListExprClass:
+      VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::MemberExprClass:
+      VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
+      break;
+    case Stmt::ObjCIvarRefExprClass:
+      VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::ObjCForCollectionStmtClass:
+      VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
+      break;
+
+    case Stmt::ObjCMessageExprClass:
+      VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::ObjCAtThrowStmtClass: {
+      // FIXME: This is not complete.  We basically treat @throw as
+      // an abort.
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      Builder->BuildSinks = true;
+      MakeNode(Dst, S, Pred, GetState(Pred));
+      break;
+    }
+
+    case Stmt::ReturnStmtClass:
+      VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
+      break;
+
+    case Stmt::OffsetOfExprClass:
+      VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::SizeOfAlignOfExprClass:
+      VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
+      break;
+
+    case Stmt::StmtExprClass: {
+      const StmtExpr* SE = cast<StmtExpr>(S);
+
+      if (SE->getSubStmt()->body_empty()) {
+        // Empty statement expression.
+        assert(SE->getType() == getContext().VoidTy
+               && "Empty statement expression must have void type.");
+        Dst.Add(Pred);
+        break;
+      }
+
+      if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
+        const GRState* state = GetState(Pred);
+        MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr)));
+      }
+      else
+        Dst.Add(Pred);
+
+      break;
+    }
+
+    case Stmt::StringLiteralClass: {
+      const GRState* state = GetState(Pred);
+      SVal V = state->getLValue(cast<StringLiteral>(S));
+      MakeNode(Dst, S, Pred, state->BindExpr(S, V));
+      return;
+    }
+
+    case Stmt::SwitchStmtClass:
+      // This case isn't for branch processing, but for handling the
+      // initialization of a condition variable.
+      VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst);
+      break;
+
+    case Stmt::UnaryOperatorClass: {
+      const UnaryOperator *U = cast<UnaryOperator>(S);
+      if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) {
+        ExplodedNodeSet Tmp;
+        VisitUnaryOperator(U, Pred, Tmp);
+        evalEagerlyAssume(Dst, Tmp, U);
+      }
+      else
+        VisitUnaryOperator(U, Pred, Dst);
+      break;
+    }
+
+    case Stmt::WhileStmtClass:
+      // This case isn't for branch processing, but for handling the
+      // initialization of a condition variable.
+      VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
+      break;
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Block entrance.  (Update counters).
+//===----------------------------------------------------------------------===//
+
+bool ExprEngine::ProcessBlockEntrance(const CFGBlock* B, 
+                                        const ExplodedNode *Pred,
+                                        BlockCounter BC) {
+  return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), 
+                          B->getBlockID()) < AMgr.getMaxVisit();
+}
+
+//===----------------------------------------------------------------------===//
+// Generic node creation.
+//===----------------------------------------------------------------------===//
+
+ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
+                                     ExplodedNode* Pred, const GRState* St,
+                                     ProgramPoint::Kind K, const void *tag) {
+  assert (Builder && "StmtNodeBuilder not present.");
+  SaveAndRestore<const void*> OldTag(Builder->Tag);
+  Builder->Tag = tag;
+  return Builder->MakeNode(Dst, S, Pred, St, K);
+}
+
+//===----------------------------------------------------------------------===//
+// Branch processing.
+//===----------------------------------------------------------------------===//
+
+const GRState* ExprEngine::MarkBranch(const GRState* state,
+                                        const Stmt* Terminator,
+                                        bool branchTaken) {
+
+  switch (Terminator->getStmtClass()) {
+    default:
+      return state;
+
+    case Stmt::BinaryOperatorClass: { // '&&' and '||'
+
+      const BinaryOperator* B = cast<BinaryOperator>(Terminator);
+      BinaryOperator::Opcode Op = B->getOpcode();
+
+      assert (Op == BO_LAnd || Op == BO_LOr);
+
+      // For &&, if we take the true branch, then the value of the whole
+      // expression is that of the RHS expression.
+      //
+      // For ||, if we take the false branch, then the value of the whole
+      // expression is that of the RHS expression.
+
+      const Expr* Ex = (Op == BO_LAnd && branchTaken) ||
+                       (Op == BO_LOr && !branchTaken)
+                       ? B->getRHS() : B->getLHS();
+
+      return state->BindExpr(B, UndefinedVal(Ex));
+    }
+
+    case Stmt::ConditionalOperatorClass: { // ?:
+
+      const ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
+
+      // For ?, if branchTaken == true then the value is either the LHS or
+      // the condition itself. (GNU extension).
+
+      const Expr* Ex;
+
+      if (branchTaken)
+        Ex = C->getLHS() ? C->getLHS() : C->getCond();
+      else
+        Ex = C->getRHS();
+
+      return state->BindExpr(C, UndefinedVal(Ex));
+    }
+
+    case Stmt::ChooseExprClass: { // ?:
+
+      const ChooseExpr* C = cast<ChooseExpr>(Terminator);
+
+      const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
+      return state->BindExpr(C, UndefinedVal(Ex));
+    }
+  }
+}
+
+/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
+/// to try to recover some path-sensitivity for casts of symbolic
+/// integers that promote their values (which are currently not tracked well).
+/// This function returns the SVal bound to Condition->IgnoreCasts if all the
+//  cast(s) did was sign-extend the original value.
+static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
+                                const Stmt* Condition, ASTContext& Ctx) {
+
+  const Expr *Ex = dyn_cast<Expr>(Condition);
+  if (!Ex)
+    return UnknownVal();
+
+  uint64_t bits = 0;
+  bool bitsInit = false;
+
+  while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
+    QualType T = CE->getType();
+
+    if (!T->isIntegerType())
+      return UnknownVal();
+
+    uint64_t newBits = Ctx.getTypeSize(T);
+    if (!bitsInit || newBits < bits) {
+      bitsInit = true;
+      bits = newBits;
+    }
+
+    Ex = CE->getSubExpr();
+  }
+
+  // We reached a non-cast.  Is it a symbolic value?
+  QualType T = Ex->getType();
+
+  if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
+    return UnknownVal();
+
+  return state->getSVal(Ex);
+}
+
+void ExprEngine::ProcessBranch(const Stmt* Condition, const Stmt* Term,
+                                 BranchNodeBuilder& builder) {
+
+  // Check for NULL conditions; e.g. "for(;;)"
+  if (!Condition) {
+    builder.markInfeasible(false);
+    return;
+  }
+
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+                                Condition->getLocStart(),
+                                "Error evaluating branch");
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+    void *tag = I->first;
+    Checker *checker = I->second;
+    checker->VisitBranchCondition(builder, *this, Condition, tag);
+  }
+
+  // If the branch condition is undefined, return;
+  if (!builder.isFeasible(true) && !builder.isFeasible(false))
+    return;
+
+  const GRState* PrevState = builder.getState();
+  SVal X = PrevState->getSVal(Condition);
+
+  if (X.isUnknown()) {
+    // Give it a chance to recover from unknown.
+    if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
+      if (Ex->getType()->isIntegerType()) {
+        // Try to recover some path-sensitivity.  Right now casts of symbolic
+        // integers that promote their values are currently not tracked well.
+        // If 'Condition' is such an expression, try and recover the
+        // underlying value and use that instead.
+        SVal recovered = RecoverCastedSymbol(getStateManager(),
+                                             builder.getState(), Condition,
+                                             getContext());
+
+        if (!recovered.isUnknown()) {
+          X = recovered;
+        }
+      }
+    }
+    // If the condition is still unknown, give up.
+    if (X.isUnknown()) {
+      builder.generateNode(MarkBranch(PrevState, Term, true), true);
+      builder.generateNode(MarkBranch(PrevState, Term, false), false);
+      return;
+    }
+  }
+
+  DefinedSVal V = cast<DefinedSVal>(X);
+
+  // Process the true branch.
+  if (builder.isFeasible(true)) {
+    if (const GRState *state = PrevState->assume(V, true))
+      builder.generateNode(MarkBranch(state, Term, true), true);
+    else
+      builder.markInfeasible(true);
+  }
+
+  // Process the false branch.
+  if (builder.isFeasible(false)) {
+    if (const GRState *state = PrevState->assume(V, false))
+      builder.generateNode(MarkBranch(state, Term, false), false);
+    else
+      builder.markInfeasible(false);
+  }
+}
+
+/// ProcessIndirectGoto - Called by CoreEngine.  Used to generate successor
+///  nodes by processing the 'effects' of a computed goto jump.
+void ExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) {
+
+  const GRState *state = builder.getState();
+  SVal V = state->getSVal(builder.getTarget());
+
+  // Three possibilities:
+  //
+  //   (1) We know the computed label.
+  //   (2) The label is NULL (or some other constant), or Undefined.
+  //   (3) We have no clue about the label.  Dispatch to all targets.
+  //
+
+  typedef IndirectGotoNodeBuilder::iterator iterator;
+
+  if (isa<loc::GotoLabel>(V)) {
+    const LabelStmt* L = cast<loc::GotoLabel>(V).getLabel();
+
+    for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
+      if (I.getLabel() == L) {
+        builder.generateNode(I, state);
+        return;
+      }
+    }
+
+    assert (false && "No block with label.");
+    return;
+  }
+
+  if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
+    // Dispatch to the first target and mark it as a sink.
+    //ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
+    // FIXME: add checker visit.
+    //    UndefBranches.insert(N);
+    return;
+  }
+
+  // This is really a catch-all.  We don't support symbolics yet.
+  // FIXME: Implement dispatch for symbolic pointers.
+
+  for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
+    builder.generateNode(I, state);
+}
+
+
+void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, 
+                                    const Expr* R,
+                                    ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+
+  assert(Ex == currentStmt &&
+         Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
+
+  const GRState* state = GetState(Pred);
+  SVal X = state->getSVal(Ex);
+
+  assert (X.isUndef());
+
+  const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
+  assert(SE);
+  X = state->getSVal(SE);
+
+  // Make sure that we invalidate the previous binding.
+  MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
+}
+
+/// ProcessEndPath - Called by CoreEngine.  Used to generate end-of-path
+///  nodes when the control reaches the end of a function.
+void ExprEngine::ProcessEndPath(EndPathNodeBuilder& builder) {
+  getTF().evalEndPath(*this, builder);
+  StateMgr.EndPath(builder.getState());
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
+    void *tag = I->first;
+    Checker *checker = I->second;
+    checker->evalEndPath(builder, tag, *this);
+  }
+}
+
+/// ProcessSwitch - Called by CoreEngine.  Used to generate successor
+///  nodes by processing the 'effects' of a switch statement.
+void ExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
+  typedef SwitchNodeBuilder::iterator iterator;
+  const GRState* state = builder.getState();
+  const Expr* CondE = builder.getCondition();
+  SVal  CondV_untested = state->getSVal(CondE);
+
+  if (CondV_untested.isUndef()) {
+    //ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
+    // FIXME: add checker
+    //UndefBranches.insert(N);
+
+    return;
+  }
+  DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
+
+  const GRState *DefaultSt = state;
+  
+  iterator I = builder.begin(), EI = builder.end();
+  bool defaultIsFeasible = I == EI;
+
+  for ( ; I != EI; ++I) {
+    const CaseStmt* Case = I.getCase();
+
+    // Evaluate the LHS of the case value.
+    Expr::EvalResult V1;
+    bool b = Case->getLHS()->Evaluate(V1, getContext());
+
+    // Sanity checks.  These go away in Release builds.
+    assert(b && V1.Val.isInt() && !V1.HasSideEffects
+             && "Case condition must evaluate to an integer constant.");
+    (void)b; // silence unused variable warning
+    assert(V1.Val.getInt().getBitWidth() ==
+           getContext().getTypeSize(CondE->getType()));
+
+    // Get the RHS of the case, if it exists.
+    Expr::EvalResult V2;
+
+    if (const Expr* E = Case->getRHS()) {
+      b = E->Evaluate(V2, getContext());
+      assert(b && V2.Val.isInt() && !V2.HasSideEffects
+             && "Case condition must evaluate to an integer constant.");
+      (void)b; // silence unused variable warning
+    }
+    else
+      V2 = V1;
+
+    // FIXME: Eventually we should replace the logic below with a range
+    //  comparison, rather than concretize the values within the range.
+    //  This should be easy once we have "ranges" for NonLVals.
+
+    do {
+      nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
+      DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state,
+                                               CondV, CaseVal);
+
+      // Now "assume" that the case matches.
+      if (const GRState* stateNew = state->assume(Res, true)) {
+        builder.generateCaseStmtNode(I, stateNew);
+
+        // If CondV evaluates to a constant, then we know that this
+        // is the *only* case that we can take, so stop evaluating the
+        // others.
+        if (isa<nonloc::ConcreteInt>(CondV))
+          return;
+      }
+
+      // Now "assume" that the case doesn't match.  Add this state
+      // to the default state (if it is feasible).
+      if (DefaultSt) {
+        if (const GRState *stateNew = DefaultSt->assume(Res, false)) {
+          defaultIsFeasible = true;
+          DefaultSt = stateNew;
+        }
+        else {
+          defaultIsFeasible = false;
+          DefaultSt = NULL;
+        }
+      }
+
+      // Concretize the next value in the range.
+      if (V1.Val.getInt() == V2.Val.getInt())
+        break;
+
+      ++V1.Val.getInt();
+      assert (V1.Val.getInt() <= V2.Val.getInt());
+
+    } while (true);
+  }
+
+  if (!defaultIsFeasible)
+    return;
+
+  // If we have switch(enum value), the default branch is not
+  // feasible if all of the enum constants not covered by 'case:' statements
+  // are not feasible values for the switch condition.
+  //
+  // Note that this isn't as accurate as it could be.  Even if there isn't
+  // a case for a particular enum value as long as that enum value isn't
+  // feasible then it shouldn't be considered for making 'default:' reachable.
+  const SwitchStmt *SS = builder.getSwitch();
+  const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts();
+  if (CondExpr->getType()->getAs<EnumType>()) {
+    if (SS->isAllEnumCasesCovered())
+      return;
+  }
+
+  builder.generateDefaultCaseNode(DefaultSt);
+}
+
+void ExprEngine::ProcessCallEnter(CallEnterNodeBuilder &B) {
+  const GRState *state = B.getState()->EnterStackFrame(B.getCalleeContext());
+  B.generateNode(state);
+}
+
+void ExprEngine::ProcessCallExit(CallExitNodeBuilder &B) {
+  const GRState *state = B.getState();
+  const ExplodedNode *Pred = B.getPredecessor();
+  const StackFrameContext *calleeCtx = 
+                            cast<StackFrameContext>(Pred->getLocationContext());
+  const Stmt *CE = calleeCtx->getCallSite();
+
+  // If the callee returns an expression, bind its value to CallExpr.
+  const Stmt *ReturnedExpr = state->get<ReturnExpr>();
+  if (ReturnedExpr) {
+    SVal RetVal = state->getSVal(ReturnedExpr);
+    state = state->BindExpr(CE, RetVal);
+    // Clear the return expr GDM.
+    state = state->remove<ReturnExpr>();
+  }
+
+  // Bind the constructed object value to CXXConstructExpr.
+  if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
+    const CXXThisRegion *ThisR =
+      getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx);
+
+    SVal ThisV = state->getSVal(ThisR);
+    // Always bind the region to the CXXConstructExpr.
+    state = state->BindExpr(CCE, ThisV);
+  }
+
+  B.generateNode(state);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: logical operations ('&&', '||').
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
+                                    ExplodedNodeSet& Dst) {
+
+  assert(B->getOpcode() == BO_LAnd ||
+         B->getOpcode() == BO_LOr);
+
+  assert(B==currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
+
+  const GRState* state = GetState(Pred);
+  SVal X = state->getSVal(B);
+  assert(X.isUndef());
+
+  const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
+  assert(Ex);
+
+  if (Ex == B->getRHS()) {
+    X = state->getSVal(Ex);
+
+    // Handle undefined values.
+    if (X.isUndef()) {
+      MakeNode(Dst, B, Pred, state->BindExpr(B, X));
+      return;
+    }
+
+    DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
+
+    // We took the RHS.  Because the value of the '&&' or '||' expression must
+    // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
+    // or 1.  Alternatively, we could take a lazy approach, and calculate this
+    // value later when necessary.  We don't have the machinery in place for
+    // this right now, and since most logical expressions are used for branches,
+    // the payoff is not likely to be large.  Instead, we do eager evaluation.
+    if (const GRState *newState = state->assume(XD, true))
+      MakeNode(Dst, B, Pred,
+               newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType())));
+
+    if (const GRState *newState = state->assume(XD, false))
+      MakeNode(Dst, B, Pred,
+               newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType())));
+  }
+  else {
+    // We took the LHS expression.  Depending on whether we are '&&' or
+    // '||' we know what the value of the expression is via properties of
+    // the short-circuiting.
+    X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
+                          B->getType());
+    MakeNode(Dst, B, Pred, state->BindExpr(B, X));
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: Loads and stores.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
+                                  ExplodedNodeSet &Dst) {
+
+  ExplodedNodeSet Tmp;
+
+  CanQualType T = getContext().getCanonicalType(BE->getType());
+  SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
+                                  Pred->getLocationContext());
+
+  MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
+           ProgramPoint::PostLValueKind);
+
+  // Post-visit the BlockExpr.
+  CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback);
+}
+
+void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
+                                        ExplodedNode *Pred,
+                                        ExplodedNodeSet &Dst) {
+  const GRState *state = GetState(Pred);
+
+  if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
+    assert(Ex->isLValue());
+    SVal V = state->getLValue(VD, Pred->getLocationContext());
+
+    // For references, the 'lvalue' is the pointer address stored in the
+    // reference region.
+    if (VD->getType()->isReferenceType()) {
+      if (const MemRegion *R = V.getAsRegion())
+        V = state->getSVal(R);
+      else
+        V = UnknownVal();
+    }
+
+    MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
+             ProgramPoint::PostLValueKind);
+    return;
+  }
+  if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
+    assert(!Ex->isLValue());
+    SVal V = svalBuilder.makeIntVal(ED->getInitVal());
+    MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
+    return;
+  }
+  if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
+    SVal V = svalBuilder.getFunctionPointer(FD);
+    MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
+             ProgramPoint::PostLValueKind);
+    return;
+  }
+  assert (false &&
+          "ValueDecl support for this ValueDecl not implemented.");
+}
+
+/// VisitArraySubscriptExpr - Transfer function for array accesses
+void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A,
+                                             ExplodedNode* Pred,
+                                             ExplodedNodeSet& Dst){
+
+  const Expr* Base = A->getBase()->IgnoreParens();
+  const Expr* Idx  = A->getIdx()->IgnoreParens();
+  
+  // Evaluate the base.
+  ExplodedNodeSet Tmp;
+  Visit(Base, Pred, Tmp);
+
+  for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
+    ExplodedNodeSet Tmp2;
+    Visit(Idx, *I1, Tmp2);     // Evaluate the index.
+    ExplodedNodeSet Tmp3;
+    CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback);
+
+    for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
+      const GRState* state = GetState(*I2);
+      SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
+                                state->getSVal(Base));
+      assert(A->isLValue());
+      MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind);
+    }
+  }
+}
+
+/// VisitMemberExpr - Transfer function for member expressions.
+void ExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
+                                 ExplodedNodeSet& Dst) {
+
+  Expr *baseExpr = M->getBase()->IgnoreParens();
+  ExplodedNodeSet dstBase;
+  Visit(baseExpr, Pred, dstBase);
+
+  FieldDecl *field = dyn_cast<FieldDecl>(M->getMemberDecl());
+  if (!field) // FIXME: skipping member expressions for non-fields
+    return;
+
+  for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
+    I != E; ++I) {
+    const GRState* state = GetState(*I);
+    SVal baseExprVal = state->getSVal(baseExpr);
+    if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
+        isa<nonloc::CompoundVal>(baseExprVal)) {
+      MakeNode(Dst, M, *I, state->BindExpr(M, UnknownVal()));
+      continue;
+    }
+
+    // FIXME: Should we insert some assumption logic in here to determine
+    // if "Base" is a valid piece of memory?  Before we put this assumption
+    // later when using FieldOffset lvals (which we no longer have).
+
+    // For all other cases, compute an lvalue.    
+    SVal L = state->getLValue(field, baseExprVal);
+    if (M->isLValue())
+      MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
+    else
+      evalLoad(Dst, M, *I, state, L);
+  }
+}
+
+/// evalBind - Handle the semantics of binding a value to a specific location.
+///  This method is used by evalStore and (soon) VisitDeclStmt, and others.
+void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE,
+                            ExplodedNode* Pred, const GRState* state,
+                            SVal location, SVal Val, bool atDeclInit) {
+
+
+  // Do a previsit of the bind.
+  ExplodedNodeSet CheckedSet, Src;
+  Src.Add(Pred);
+  CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true);
+
+  for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+       I!=E; ++I) {
+
+    if (Pred != *I)
+      state = GetState(*I);
+
+    const GRState* newState = 0;
+
+    if (atDeclInit) {
+      const VarRegion *VR =
+        cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
+
+      newState = state->bindDecl(VR, Val);
+    }
+    else {
+      if (location.isUnknown()) {
+        // We know that the new state will be the same as the old state since
+        // the location of the binding is "unknown".  Consequently, there
+        // is no reason to just create a new node.
+        newState = state;
+      }
+      else {
+        // We are binding to a value other than 'unknown'.  Perform the binding
+        // using the StoreManager.
+        newState = state->bindLoc(cast<Loc>(location), Val);
+      }
+    }
+
+    // The next thing to do is check if the TransferFuncs object wants to
+    // update the state based on the new binding.  If the GRTransferFunc object
+    // doesn't do anything, just auto-propagate the current state.
+    
+    // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE'
+    // is non-NULL.  Checkers typically care about 
+    
+    StmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE,
+                                    true);
+
+    getTF().evalBind(BuilderRef, location, Val);
+  }
+}
+
+/// evalStore - Handle the semantics of a store via an assignment.
+///  @param Dst The node set to store generated state nodes
+///  @param AssignE The assignment expression if the store happens in an 
+///         assignment.
+///  @param LocatioinE The location expression that is stored to.
+///  @param state The current simulation state
+///  @param location The location to store the value
+///  @param Val The value to be stored
+void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
+                             const Expr* LocationE,
+                             ExplodedNode* Pred,
+                             const GRState* state, SVal location, SVal Val,
+                             const void *tag) {
+
+  assert(Builder && "StmtNodeBuilder must be defined.");
+
+  // Evaluate the location (checks for bad dereferences).
+  ExplodedNodeSet Tmp;
+  evalLocation(Tmp, LocationE, Pred, state, location, tag, false);
+
+  if (Tmp.empty())
+    return;
+
+  assert(!location.isUndef());
+
+  SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
+                                                   ProgramPoint::PostStoreKind);
+  SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
+
+  // Proceed with the store.  We use AssignE as the anchor for the PostStore
+  // ProgramPoint if it is non-NULL, and LocationE otherwise.
+  const Expr *StoreE = AssignE ? AssignE : LocationE;
+
+  for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+    evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val);
+}
+
+void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
+                            ExplodedNode* Pred,
+                            const GRState* state, SVal location,
+                            const void *tag, QualType LoadTy) {
+  assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
+
+  // Are we loading from a region?  This actually results in two loads; one
+  // to fetch the address of the referenced value and one to fetch the
+  // referenced value.
+  if (const TypedRegion *TR =
+        dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+
+    QualType ValTy = TR->getValueType();
+    if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
+      static int loadReferenceTag = 0;
+      ExplodedNodeSet Tmp;
+      evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
+                     getContext().getPointerType(RT->getPointeeType()));
+
+      // Perform the load from the referenced value.
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
+        state = GetState(*I);
+        location = state->getSVal(Ex);
+        evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
+      }
+      return;
+    }
+  }
+
+  evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
+}
+
+void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
+                                  ExplodedNode* Pred,
+                                  const GRState* state, SVal location,
+                                  const void *tag, QualType LoadTy) {
+
+  // Evaluate the location (checks for bad dereferences).
+  ExplodedNodeSet Tmp;
+  evalLocation(Tmp, Ex, Pred, state, location, tag, true);
+
+  if (Tmp.empty())
+    return;
+
+  assert(!location.isUndef());
+
+  SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
+  SaveAndRestore<const void*> OldTag(Builder->Tag);
+
+  // Proceed with the load.
+  for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+    state = GetState(*NI);
+
+    if (location.isUnknown()) {
+      // This is important.  We must nuke the old binding.
+      MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
+               ProgramPoint::PostLoadKind, tag);
+    }
+    else {
+      if (LoadTy.isNull())
+        LoadTy = Ex->getType();
+      SVal V = state->getSVal(cast<Loc>(location), LoadTy);
+      MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V),
+               ProgramPoint::PostLoadKind, tag);
+    }
+  }
+}
+
+void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
+                                ExplodedNode* Pred,
+                                const GRState* state, SVal location,
+                                const void *tag, bool isLoad) {
+  // Early checks for performance reason.
+  if (location.isUnknown() || Checkers.empty()) {
+    Dst.Add(Pred);
+    return;
+  }
+
+  ExplodedNodeSet Src, Tmp;
+  Src.Add(Pred);
+  ExplodedNodeSet *PrevSet = &Src;
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+  {
+    ExplodedNodeSet *CurrSet = 0;
+    if (I+1 == E)
+      CurrSet = &Dst;
+    else {
+      CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+      CurrSet->clear();
+    }
+
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI) {
+      // Use the 'state' argument only when the predecessor node is the
+      // same as Pred.  This allows us to catch updates to the state.
+      checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI,
+                                *NI == Pred ? state : GetState(*NI),
+                                location, tag, isLoad);
+    }
+
+    // Update which NodeSet is the current one.
+    PrevSet = CurrSet;
+  }
+}
+
+bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, 
+                              ExplodedNode *Pred) {
+  const GRState *state = GetState(Pred);
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+  
+  const FunctionDecl *FD = L.getAsFunctionDecl();
+  if (!FD)
+    return false;
+
+  // Check if the function definition is in the same translation unit.
+  if (FD->hasBody(FD)) {
+    const StackFrameContext *stackFrame = 
+      AMgr.getStackFrame(AMgr.getAnalysisContext(FD), 
+                         Pred->getLocationContext(),
+                         CE, Builder->getBlock(), Builder->getIndex());
+    // Now we have the definition of the callee, create a CallEnter node.
+    CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
+
+    ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+    Dst.Add(N);
+    return true;
+  }
+
+  // Check if we can find the function definition in other translation units.
+  if (AMgr.hasIndexer()) {
+    AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD);
+    if (C == 0)
+      return false;
+    const StackFrameContext *stackFrame = 
+      AMgr.getStackFrame(C, Pred->getLocationContext(),
+                         CE, Builder->getBlock(), Builder->getIndex());
+    CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
+    ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+    Dst.Add(N);
+    return true;
+  }
+
+  return false;
+}
+
+void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
+                             CallExpr::const_arg_iterator AI,
+                             CallExpr::const_arg_iterator AE,
+                             ExplodedNodeSet& Dst) {
+
+  // Determine the type of function we're calling (if available).
+  const FunctionProtoType *Proto = NULL;
+  QualType FnType = CE->getCallee()->IgnoreParens()->getType();
+  if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
+    Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
+
+  // Evaluate the arguments.
+  ExplodedNodeSet ArgsEvaluated;
+  evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated);
+
+  // Now process the call itself.
+  ExplodedNodeSet DstTmp;
+  const Expr* Callee = CE->getCallee()->IgnoreParens();
+
+  for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
+                                 NE=ArgsEvaluated.end(); NI != NE; ++NI) {
+    // Evaluate the callee.
+    ExplodedNodeSet DstTmp2;
+    Visit(Callee, *NI, DstTmp2);
+    // Perform the previsit of the CallExpr, storing the results in DstTmp.
+    CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback);
+  }
+
+  // Finally, evaluate the function call.  We try each of the checkers
+  // to see if the can evaluate the function call.
+  ExplodedNodeSet DstTmp3;
+
+  for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
+       DI != DE; ++DI) {
+
+    const GRState* state = GetState(*DI);
+    SVal L = state->getSVal(Callee);
+
+    // FIXME: Add support for symbolic function calls (calls involving
+    //  function pointer values that are symbolic).
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    ExplodedNodeSet DstChecker;
+
+    // If the callee is processed by a checker, skip the rest logic.
+    if (CheckerEvalCall(CE, DstChecker, *DI))
+      DstTmp3.insert(DstChecker);
+    else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) {
+      // Callee is inlined. We shouldn't do post call checking.
+      return;
+    }
+    else {
+      for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
+           DE_Checker = DstChecker.end();
+           DI_Checker != DE_Checker; ++DI_Checker) {
+
+        // Dispatch to the plug-in transfer function.
+        unsigned oldSize = DstTmp3.size();
+        SaveOr OldHasGen(Builder->HasGeneratedNode);
+        Pred = *DI_Checker;
+
+        // Dispatch to transfer function logic to handle the call itself.
+        // FIXME: Allow us to chain together transfer functions.
+        assert(Builder && "StmtNodeBuilder must be defined.");
+        getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred);
+
+        // Handle the case where no nodes where generated.  Auto-generate that
+        // contains the updated state if we aren't generating sinks.
+        if (!Builder->BuildSinks && DstTmp3.size() == oldSize &&
+            !Builder->HasGeneratedNode)
+          MakeNode(DstTmp3, CE, Pred, state);
+      }
+    }
+  }
+
+  // Finally, perform the post-condition check of the CallExpr and store
+  // the created nodes in 'Dst'.
+  CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C ivar references.
+//===----------------------------------------------------------------------===//
+
+static std::pair<const void*,const void*> EagerlyAssumeTag
+  = std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0));
+
+void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+                                     const Expr *Ex) {
+  for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
+    ExplodedNode *Pred = *I;
+
+    // Test if the previous node was as the same expression.  This can happen
+    // when the expression fails to evaluate to anything meaningful and
+    // (as an optimization) we don't generate a node.
+    ProgramPoint P = Pred->getLocation();
+    if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
+      Dst.Add(Pred);
+      continue;
+    }
+
+    const GRState* state = GetState(Pred);
+    SVal V = state->getSVal(Ex);
+    if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
+      // First assume that the condition is true.
+      if (const GRState *stateTrue = state->assume(*SEV, true)) {
+        stateTrue = stateTrue->BindExpr(Ex,
+                                        svalBuilder.makeIntVal(1U, Ex->getType()));
+        Dst.Add(Builder->generateNode(PostStmtCustom(Ex,
+                                &EagerlyAssumeTag, Pred->getLocationContext()),
+                                      stateTrue, Pred));
+      }
+
+      // Next, assume that the condition is false.
+      if (const GRState *stateFalse = state->assume(*SEV, false)) {
+        stateFalse = stateFalse->BindExpr(Ex,
+                                          svalBuilder.makeIntVal(0U, Ex->getType()));
+        Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag,
+                                                   Pred->getLocationContext()),
+                                      stateFalse, Pred));
+      }
+    }
+    else
+      Dst.Add(Pred);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C @synchronized.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
+                                               ExplodedNode *Pred,
+                                               ExplodedNodeSet &Dst) {
+
+  // The mutex expression is a CFGElement, so we don't need to explicitly
+  // visit it since it will already be processed.
+
+  // Pre-visit the ObjCAtSynchronizedStmt.
+  ExplodedNodeSet Tmp;
+  Tmp.Add(Pred);
+  CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C ivar references.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, 
+                                          ExplodedNode* Pred,
+                                          ExplodedNodeSet& Dst) {
+
+  // Visit the base expression, which is needed for computing the lvalue
+  // of the ivar.
+  ExplodedNodeSet dstBase;
+  const Expr *baseExpr = Ex->getBase();
+  Visit(baseExpr, Pred, dstBase);
+
+  // Using the base, compute the lvalue of the instance variable.
+  for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
+       I!=E; ++I) {
+    ExplodedNode *nodeBase = *I;
+    const GRState *state = GetState(nodeBase);
+    SVal baseVal = state->getSVal(baseExpr);
+    SVal location = state->getLValue(Ex->getDecl(), baseVal);
+    MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location));
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C fast enumeration 'for' statements.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
+                                     ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+
+  // ObjCForCollectionStmts are processed in two places.  This method
+  // handles the case where an ObjCForCollectionStmt* occurs as one of the
+  // statements within a basic block.  This transfer function does two things:
+  //
+  //  (1) binds the next container value to 'element'.  This creates a new
+  //      node in the ExplodedGraph.
+  //
+  //  (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
+  //      whether or not the container has any more elements.  This value
+  //      will be tested in ProcessBranch.  We need to explicitly bind
+  //      this value because a container can contain nil elements.
+  //
+  // FIXME: Eventually this logic should actually do dispatches to
+  //   'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
+  //   This will require simulating a temporary NSFastEnumerationState, either
+  //   through an SVal or through the use of MemRegions.  This value can
+  //   be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
+  //   terminates we reclaim the temporary (it goes out of scope) and we
+  //   we can test if the SVal is 0 or if the MemRegion is null (depending
+  //   on what approach we take).
+  //
+  //  For now: simulate (1) by assigning either a symbol or nil if the
+  //    container is empty.  Thus this transfer function will by default
+  //    result in state splitting.
+
+  const Stmt* elem = S->getElement();
+  SVal ElementV;
+
+  if (const DeclStmt* DS = dyn_cast<DeclStmt>(elem)) {
+    const VarDecl* ElemD = cast<VarDecl>(DS->getSingleDecl());
+    assert (ElemD->getInit() == 0);
+    ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext());
+    VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  Visit(cast<Expr>(elem), Pred, Tmp);
+  for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+    const GRState* state = GetState(*I);
+    VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem));
+  }
+}
+
+void ExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
+                                       ExplodedNode* Pred, ExplodedNodeSet& Dst,
+                                                 SVal ElementV) {
+
+  // Check if the location we are writing back to is a null pointer.
+  const Stmt* elem = S->getElement();
+  ExplodedNodeSet Tmp;
+  evalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
+
+  if (Tmp.empty())
+    return;
+
+  for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+    Pred = *NI;
+    const GRState *state = GetState(Pred);
+
+    // Handle the case where the container still has elements.
+    SVal TrueV = svalBuilder.makeTruthVal(1);
+    const GRState *hasElems = state->BindExpr(S, TrueV);
+
+    // Handle the case where the container has no elements.
+    SVal FalseV = svalBuilder.makeTruthVal(0);
+    const GRState *noElems = state->BindExpr(S, FalseV);
+
+    if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
+      if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
+        // FIXME: The proper thing to do is to really iterate over the
+        //  container.  We will do this with dispatch logic to the store.
+        //  For now, just 'conjure' up a symbolic value.
+        QualType T = R->getValueType();
+        assert(Loc::IsLocType(T));
+        unsigned Count = Builder->getCurrentBlockCount();
+        SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+        SVal V = svalBuilder.makeLoc(Sym);
+        hasElems = hasElems->bindLoc(ElementV, V);
+
+        // Bind the location to 'nil' on the false branch.
+        SVal nilV = svalBuilder.makeIntVal(0, T);
+        noElems = noElems->bindLoc(ElementV, nilV);
+      }
+
+    // Create the new nodes.
+    MakeNode(Dst, S, Pred, hasElems);
+    MakeNode(Dst, S, Pred, noElems);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function: Objective-C message expressions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ObjCMsgWLItem {
+public:
+  ObjCMessageExpr::const_arg_iterator I;
+  ExplodedNode *N;
+
+  ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n)
+    : I(i), N(n) {}
+};
+} // end anonymous namespace
+
+void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, 
+                                        ExplodedNode* Pred,
+                                        ExplodedNodeSet& Dst){
+
+  // Create a worklist to process both the arguments.
+  llvm::SmallVector<ObjCMsgWLItem, 20> WL;
+
+  // But first evaluate the receiver (if any).
+  ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
+  if (const Expr *Receiver = ME->getInstanceReceiver()) {
+    ExplodedNodeSet Tmp;
+    Visit(Receiver, Pred, Tmp);
+
+    if (Tmp.empty())
+      return;
+
+    for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
+      WL.push_back(ObjCMsgWLItem(AI, *I));
+  }
+  else
+    WL.push_back(ObjCMsgWLItem(AI, Pred));
+
+  // Evaluate the arguments.
+  ExplodedNodeSet ArgsEvaluated;
+  while (!WL.empty()) {
+    ObjCMsgWLItem Item = WL.back();
+    WL.pop_back();
+
+    if (Item.I == AE) {
+      ArgsEvaluated.insert(Item.N);
+      continue;
+    }
+
+    // Evaluate the subexpression.
+    ExplodedNodeSet Tmp;
+
+    // FIXME: [Objective-C++] handle arguments that are references
+    Visit(*Item.I, Item.N, Tmp);
+
+    // Enqueue evaluating the next argument on the worklist.
+    ++(Item.I);
+    for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+      WL.push_back(ObjCMsgWLItem(Item.I, *NI));
+  }
+
+  // Now that the arguments are processed, handle the previsits checks.
+  ExplodedNodeSet DstPrevisit;
+  CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback);
+
+  // Proceed with evaluate the message expression.
+  ExplodedNodeSet dstEval;
+
+  for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
+                                 DE = DstPrevisit.end(); DI != DE; ++DI) {
+
+    Pred = *DI;
+    bool RaisesException = false;
+    unsigned oldSize = dstEval.size();
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+    if (const Expr *Receiver = ME->getInstanceReceiver()) {
+      const GRState *state = GetState(Pred);
+
+      // Bifurcate the state into nil and non-nil ones.
+      DefinedOrUnknownSVal receiverVal =
+        cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+
+      const GRState *notNilState, *nilState;
+      llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+
+      // There are three cases: can be nil or non-nil, must be nil, must be
+      // non-nil. We handle must be nil, and merge the rest two into non-nil.
+      if (nilState && !notNilState) {
+        CheckerEvalNilReceiver(ME, dstEval, nilState, Pred);
+        continue;
+      }
+
+      // Check if the "raise" message was sent.
+      assert(notNilState);
+      if (ME->getSelector() == RaiseSel)
+        RaisesException = true;
+
+      // Check if we raise an exception.  For now treat these as sinks.
+      // Eventually we will want to handle exceptions properly.
+      if (RaisesException)
+        Builder->BuildSinks = true;
+
+      // Dispatch to plug-in transfer function.
+      evalObjCMessageExpr(dstEval, ME, Pred, notNilState);
+    }
+    else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
+      IdentifierInfo* ClsName = Iface->getIdentifier();
+      Selector S = ME->getSelector();
+
+      // Check for special instance methods.
+      if (!NSExceptionII) {
+        ASTContext& Ctx = getContext();
+        NSExceptionII = &Ctx.Idents.get("NSException");
+      }
+
+      if (ClsName == NSExceptionII) {
+        enum { NUM_RAISE_SELECTORS = 2 };
+
+        // Lazily create a cache of the selectors.
+        if (!NSExceptionInstanceRaiseSelectors) {
+          ASTContext& Ctx = getContext();
+          NSExceptionInstanceRaiseSelectors =
+            new Selector[NUM_RAISE_SELECTORS];
+          llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
+          unsigned idx = 0;
+
+          // raise:format:
+          II.push_back(&Ctx.Idents.get("raise"));
+          II.push_back(&Ctx.Idents.get("format"));
+          NSExceptionInstanceRaiseSelectors[idx++] =
+            Ctx.Selectors.getSelector(II.size(), &II[0]);
+
+          // raise:format::arguments:
+          II.push_back(&Ctx.Idents.get("arguments"));
+          NSExceptionInstanceRaiseSelectors[idx++] =
+            Ctx.Selectors.getSelector(II.size(), &II[0]);
+        }
+
+        for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
+          if (S == NSExceptionInstanceRaiseSelectors[i]) {
+            RaisesException = true;
+            break;
+          }
+      }
+
+      // Check if we raise an exception.  For now treat these as sinks.
+      // Eventually we will want to handle exceptions properly.
+      if (RaisesException)
+        Builder->BuildSinks = true;
+
+      // Dispatch to plug-in transfer function.
+      evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred));
+    }
+
+    // Handle the case where no nodes where generated.  Auto-generate that
+    // contains the updated state if we aren't generating sinks.
+    if (!Builder->BuildSinks && dstEval.size() == oldSize &&
+        !Builder->HasGeneratedNode)
+      MakeNode(dstEval, ME, Pred, GetState(Pred));
+  }
+
+  // Finally, perform the post-condition check of the ObjCMessageExpr and store
+  // the created nodes in 'Dst'.
+  CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: Miscellaneous statements.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, 
+                           ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+  
+  ExplodedNodeSet S1;
+  Visit(Ex, Pred, S1);
+  ExplodedNodeSet S2;
+  CheckerVisit(CastE, S2, S1, PreVisitStmtCallback);
+  
+  if (CastE->getCastKind() == CK_LValueToRValue) {
+    for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) {
+      ExplodedNode *subExprNode = *I;
+      const GRState *state = GetState(subExprNode);
+      evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex));
+    }
+    return;
+  }
+  
+  // All other casts.  
+  QualType T = CastE->getType();
+  QualType ExTy = Ex->getType();
+
+  if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
+    T = ExCast->getTypeAsWritten();
+#if 0
+  // If we are evaluating the cast in an lvalue context, we implicitly want
+  // the cast to evaluate to a location.
+  if (asLValue) {
+    ASTContext &Ctx = getContext();
+    T = Ctx.getPointerType(Ctx.getCanonicalType(T));
+    ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy));
+  }
+#endif
+
+  switch (CastE->getCastKind()) {
+  case CK_ToVoid:
+    for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
+      Dst.Add(*I);
+    return;
+
+  case CK_LValueToRValue:
+  case CK_NoOp:
+  case CK_FunctionToPointerDecay:
+    for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+      // Copy the SVal of Ex to CastE.
+      ExplodedNode *N = *I;
+      const GRState *state = GetState(N);
+      SVal V = state->getSVal(Ex);
+      state = state->BindExpr(CastE, V);
+      MakeNode(Dst, CastE, N, state);
+    }
+    return;
+
+  case CK_GetObjCProperty:
+  case CK_Dependent:
+  case CK_ArrayToPointerDecay:
+  case CK_BitCast:
+  case CK_LValueBitCast:
+  case CK_IntegralCast:
+  case CK_NullToPointer:
+  case CK_IntegralToPointer:
+  case CK_PointerToIntegral:
+  case CK_PointerToBoolean:
+  case CK_IntegralToBoolean:
+  case CK_IntegralToFloating:
+  case CK_FloatingToIntegral:
+  case CK_FloatingToBoolean:
+  case CK_FloatingCast:
+  case CK_FloatingRealToComplex:
+  case CK_FloatingComplexToReal:
+  case CK_FloatingComplexToBoolean:
+  case CK_FloatingComplexCast:
+  case CK_FloatingComplexToIntegralComplex:
+  case CK_IntegralRealToComplex:
+  case CK_IntegralComplexToReal:
+  case CK_IntegralComplexToBoolean:
+  case CK_IntegralComplexCast:
+  case CK_IntegralComplexToFloatingComplex:
+  case CK_AnyPointerToObjCPointerCast:
+  case CK_AnyPointerToBlockPointerCast:
+  
+  case CK_ObjCObjectLValueCast: {
+    // Delegate to SValBuilder to process.
+    for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+      ExplodedNode* N = *I;
+      const GRState* state = GetState(N);
+      SVal V = state->getSVal(Ex);
+      V = svalBuilder.evalCast(V, T, ExTy);
+      state = state->BindExpr(CastE, V);
+      MakeNode(Dst, CastE, N, state);
+    }
+    return;
+  }
+
+  case CK_DerivedToBase:
+  case CK_UncheckedDerivedToBase:
+    // For DerivedToBase cast, delegate to the store manager.
+    for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+      ExplodedNode *node = *I;
+      const GRState *state = GetState(node);
+      SVal val = state->getSVal(Ex);
+      val = getStoreManager().evalDerivedToBase(val, T);
+      state = state->BindExpr(CastE, val);
+      MakeNode(Dst, CastE, node, state);
+    }
+    return;
+
+  // Various C++ casts that are not handled yet.
+  case CK_Dynamic:  
+  case CK_ToUnion:
+  case CK_BaseToDerived:
+  case CK_NullToMemberPointer:
+  case CK_BaseToDerivedMemberPointer:
+  case CK_DerivedToBaseMemberPointer:
+  case CK_UserDefinedConversion:
+  case CK_ConstructorConversion:
+  case CK_VectorSplat:
+  case CK_MemberPointerToBoolean: {
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    Builder->BuildSinks = true;
+    MakeNode(Dst, CastE, Pred, GetState(Pred));
+    return;
+  }
+  }
+}
+
+void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
+                                            ExplodedNode* Pred,
+                                            ExplodedNodeSet& Dst) {
+  const InitListExpr* ILE 
+    = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
+  ExplodedNodeSet Tmp;
+  Visit(ILE, Pred, Tmp);
+
+  for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
+    const GRState* state = GetState(*I);
+    SVal ILV = state->getSVal(ILE);
+    const LocationContext *LC = (*I)->getLocationContext();
+    state = state->bindCompoundLiteral(CL, LC, ILV);
+
+    if (CL->isLValue()) {
+      MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC)));
+    }
+    else
+      MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
+  }
+}
+
+void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
+                                 ExplodedNodeSet& Dst) {
+
+  // The CFG has one DeclStmt per Decl.
+  const Decl* D = *DS->decl_begin();
+
+  if (!D || !isa<VarDecl>(D))
+    return;
+
+  const VarDecl* VD = dyn_cast<VarDecl>(D);
+  const Expr* InitEx = VD->getInit();
+
+  // FIXME: static variables may have an initializer, but the second
+  //  time a function is called those values may not be current.
+  ExplodedNodeSet Tmp;
+
+  if (InitEx) {
+    if (VD->getType()->isReferenceType() && !InitEx->isLValue()) {
+      // If the initializer is C++ record type, it should already has a 
+      // temp object.
+      if (!InitEx->getType()->isRecordType())
+        CreateCXXTemporaryObject(InitEx, Pred, Tmp);
+      else
+        Tmp.Add(Pred);
+    } else
+      Visit(InitEx, Pred, Tmp);
+  } else
+    Tmp.Add(Pred);
+
+  ExplodedNodeSet Tmp2;
+  CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback);
+
+  for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
+    ExplodedNode *N = *I;
+    const GRState *state = GetState(N);
+
+    // Decls without InitExpr are not initialized explicitly.
+    const LocationContext *LC = N->getLocationContext();
+
+    if (InitEx) {
+      SVal InitVal = state->getSVal(InitEx);
+
+      // We bound the temp obj region to the CXXConstructExpr. Now recover
+      // the lazy compound value when the variable is not a reference.
+      if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() && 
+          !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
+        InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
+        assert(isa<nonloc::LazyCompoundVal>(InitVal));
+      }
+
+      // Recover some path-sensitivity if a scalar value evaluated to
+      // UnknownVal.
+      if ((InitVal.isUnknown() ||
+          !getConstraintManager().canReasonAbout(InitVal)) &&
+          !VD->getType()->isReferenceType()) {
+        InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
+                                               Builder->getCurrentBlockCount());
+      }
+
+      evalBind(Dst, DS, *I, state,
+               loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+    }
+    else {
+      state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
+      MakeNode(Dst, DS, *I, state);
+    }
+  }
+}
+
+void ExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S,
+                                 ExplodedNode *Pred, ExplodedNodeSet& Dst) {
+
+  const Expr* InitEx = VD->getInit();
+  ExplodedNodeSet Tmp;
+  Visit(InitEx, Pred, Tmp);
+
+  for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+    ExplodedNode *N = *I;
+    const GRState *state = GetState(N);
+
+    const LocationContext *LC = N->getLocationContext();
+    SVal InitVal = state->getSVal(InitEx);
+
+    // Recover some path-sensitivity if a scalar value evaluated to
+    // UnknownVal.
+    if (InitVal.isUnknown() ||
+        !getConstraintManager().canReasonAbout(InitVal)) {
+      InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
+                                            Builder->getCurrentBlockCount());
+    }
+
+    evalBind(Dst, S, N, state,
+             loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
+  }
+}
+
+namespace {
+  // This class is used by VisitInitListExpr as an item in a worklist
+  // for processing the values contained in an InitListExpr.
+class InitListWLItem {
+public:
+  llvm::ImmutableList<SVal> Vals;
+  ExplodedNode* N;
+  InitListExpr::const_reverse_iterator Itr;
+
+  InitListWLItem(ExplodedNode* n, llvm::ImmutableList<SVal> vals,
+                 InitListExpr::const_reverse_iterator itr)
+  : Vals(vals), N(n), Itr(itr) {}
+};
+}
+
+
+void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
+                                     ExplodedNodeSet& Dst) {
+
+  const GRState* state = GetState(Pred);
+  QualType T = getContext().getCanonicalType(E->getType());
+  unsigned NumInitElements = E->getNumInits();
+
+  if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
+    llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
+
+    // Handle base case where the initializer has no elements.
+    // e.g: static int* myArray[] = {};
+    if (NumInitElements == 0) {
+      SVal V = svalBuilder.makeCompoundVal(T, StartVals);
+      MakeNode(Dst, E, Pred, state->BindExpr(E, V));
+      return;
+    }
+
+    // Create a worklist to process the initializers.
+    llvm::SmallVector<InitListWLItem, 10> WorkList;
+    WorkList.reserve(NumInitElements);
+    WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin()));
+    InitListExpr::const_reverse_iterator ItrEnd = E->rend();
+    assert(!(E->rbegin() == E->rend()));
+
+    // Process the worklist until it is empty.
+    while (!WorkList.empty()) {
+      InitListWLItem X = WorkList.back();
+      WorkList.pop_back();
+
+      ExplodedNodeSet Tmp;
+      Visit(*X.Itr, X.N, Tmp);
+
+      InitListExpr::const_reverse_iterator NewItr = X.Itr + 1;
+
+      for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) {
+        // Get the last initializer value.
+        state = GetState(*NI);
+        SVal InitV = state->getSVal(cast<Expr>(*X.Itr));
+
+        // Construct the new list of values by prepending the new value to
+        // the already constructed list.
+        llvm::ImmutableList<SVal> NewVals =
+          getBasicVals().consVals(InitV, X.Vals);
+
+        if (NewItr == ItrEnd) {
+          // Now we have a list holding all init values. Make CompoundValData.
+          SVal V = svalBuilder.makeCompoundVal(T, NewVals);
+
+          // Make final state and node.
+          MakeNode(Dst, E, *NI, state->BindExpr(E, V));
+        }
+        else {
+          // Still some initializer values to go.  Push them onto the worklist.
+          WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
+        }
+      }
+    }
+
+    return;
+  }
+
+  if (Loc::IsLocType(T) || T->isIntegerType()) {
+    assert (E->getNumInits() == 1);
+    ExplodedNodeSet Tmp;
+    const Expr* Init = E->getInit(0);
+    Visit(Init, Pred, Tmp);
+    for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) {
+      state = GetState(*I);
+      MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init)));
+    }
+    return;
+  }
+
+  assert(0 && "unprocessed InitListExpr type");
+}
+
+/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
+void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex,
+                                          ExplodedNode* Pred,
+                                          ExplodedNodeSet& Dst) {
+  QualType T = Ex->getTypeOfArgument();
+  CharUnits amt;
+
+  if (Ex->isSizeOf()) {
+    if (T == getContext().VoidTy) {
+      // sizeof(void) == 1 byte.
+      amt = CharUnits::One();
+    }
+    else if (!T->isConstantSizeType()) {
+      assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
+
+      // FIXME: Add support for VLA type arguments, not just VLA expressions.
+      // When that happens, we should probably refactor VLASizeChecker's code.
+      if (Ex->isArgumentType()) {
+        Dst.Add(Pred);
+        return;
+      }
+
+      // Get the size by getting the extent of the sub-expression.
+      // First, visit the sub-expression to find its region.
+      const Expr *Arg = Ex->getArgumentExpr();
+      ExplodedNodeSet Tmp;
+      Visit(Arg, Pred, Tmp);
+
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+        const GRState* state = GetState(*I);
+        const MemRegion *MR = state->getSVal(Arg).getAsRegion();
+
+        // If the subexpression can't be resolved to a region, we don't know
+        // anything about its size. Just leave the state as is and continue.
+        if (!MR) {
+          Dst.Add(*I);
+          continue;
+        }
+
+        // The result is the extent of the VLA.
+        SVal Extent = cast<SubRegion>(MR)->getExtent(svalBuilder);
+        MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent));
+      }
+
+      return;
+    }
+    else if (T->getAs<ObjCObjectType>()) {
+      // Some code tries to take the sizeof an ObjCObjectType, relying that
+      // the compiler has laid out its representation.  Just report Unknown
+      // for these.
+      Dst.Add(Pred);
+      return;
+    }
+    else {
+      // All other cases.
+      amt = getContext().getTypeSizeInChars(T);
+    }
+  }
+  else  // Get alignment of the type.
+    amt = getContext().getTypeAlignInChars(T);
+
+  MakeNode(Dst, Ex, Pred,
+           GetState(Pred)->BindExpr(Ex,
+              svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())));
+}
+
+void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE, 
+                                     ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+  Expr::EvalResult Res;
+  if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+    const APSInt &IV = Res.Val.getInt();
+    assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
+    assert(OOE->getType()->isIntegerType());
+    assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+    SVal X = svalBuilder.makeIntVal(IV);
+    MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
+    return;
+  }
+  // FIXME: Handle the case where __builtin_offsetof is not a constant.
+  Dst.Add(Pred);
+}
+
+void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, 
+                                      ExplodedNode* Pred,
+                                      ExplodedNodeSet& Dst) {
+
+  switch (U->getOpcode()) {
+
+    default:
+      break;
+
+    case UO_Real: {
+      const Expr* Ex = U->getSubExpr()->IgnoreParens();
+      ExplodedNodeSet Tmp;
+      Visit(Ex, Pred, Tmp);
+
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+        // FIXME: We don't have complex SValues yet.
+        if (Ex->getType()->isAnyComplexType()) {
+          // Just report "Unknown."
+          Dst.Add(*I);
+          continue;
+        }
+
+        // For all other types, UO_Real is an identity operation.
+        assert (U->getType() == Ex->getType());
+        const GRState* state = GetState(*I);
+        MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
+      }
+
+      return;
+    }
+
+    case UO_Imag: {
+
+      const Expr* Ex = U->getSubExpr()->IgnoreParens();
+      ExplodedNodeSet Tmp;
+      Visit(Ex, Pred, Tmp);
+
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+        // FIXME: We don't have complex SValues yet.
+        if (Ex->getType()->isAnyComplexType()) {
+          // Just report "Unknown."
+          Dst.Add(*I);
+          continue;
+        }
+
+        // For all other types, UO_Imag returns 0.
+        const GRState* state = GetState(*I);
+        SVal X = svalBuilder.makeZeroVal(Ex->getType());
+        MakeNode(Dst, U, *I, state->BindExpr(U, X));
+      }
+
+      return;
+    }
+      
+    case UO_Plus:
+      assert(!U->isLValue());
+      // FALL-THROUGH.
+    case UO_Deref:
+    case UO_AddrOf:
+    case UO_Extension: {
+
+      // Unary "+" is a no-op, similar to a parentheses.  We still have places
+      // where it may be a block-level expression, so we need to
+      // generate an extra node that just propagates the value of the
+      // subexpression.
+
+      const Expr* Ex = U->getSubExpr()->IgnoreParens();
+      ExplodedNodeSet Tmp;
+      Visit(Ex, Pred, Tmp);
+
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+        const GRState* state = GetState(*I);
+        MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
+      }
+
+      return;
+    }
+
+    case UO_LNot:
+    case UO_Minus:
+    case UO_Not: {
+      assert (!U->isLValue());
+      const Expr* Ex = U->getSubExpr()->IgnoreParens();
+      ExplodedNodeSet Tmp;
+      Visit(Ex, Pred, Tmp);
+
+      for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+        const GRState* state = GetState(*I);
+
+        // Get the value of the subexpression.
+        SVal V = state->getSVal(Ex);
+
+        if (V.isUnknownOrUndef()) {
+          MakeNode(Dst, U, *I, state->BindExpr(U, V));
+          continue;
+        }
+
+//        QualType DstT = getContext().getCanonicalType(U->getType());
+//        QualType SrcT = getContext().getCanonicalType(Ex->getType());
+//
+//        if (DstT != SrcT) // Perform promotions.
+//          V = evalCast(V, DstT);
+//
+//        if (V.isUnknownOrUndef()) {
+//          MakeNode(Dst, U, *I, BindExpr(St, U, V));
+//          continue;
+//        }
+
+        switch (U->getOpcode()) {
+          default:
+            assert(false && "Invalid Opcode.");
+            break;
+
+          case UO_Not:
+            // FIXME: Do we need to handle promotions?
+            state = state->BindExpr(U, evalComplement(cast<NonLoc>(V)));
+            break;
+
+          case UO_Minus:
+            // FIXME: Do we need to handle promotions?
+            state = state->BindExpr(U, evalMinus(cast<NonLoc>(V)));
+            break;
+
+          case UO_LNot:
+
+            // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
+            //
+            //  Note: technically we do "E == 0", but this is the same in the
+            //    transfer functions as "0 == E".
+            SVal Result;
+
+            if (isa<Loc>(V)) {
+              Loc X = svalBuilder.makeNull();
+              Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
+                                 U->getType());
+            }
+            else {
+              nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
+              Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
+                                 U->getType());
+            }
+
+            state = state->BindExpr(U, Result);
+
+            break;
+        }
+
+        MakeNode(Dst, U, *I, state);
+      }
+
+      return;
+    }
+  }
+
+  // Handle ++ and -- (both pre- and post-increment).
+  assert (U->isIncrementDecrementOp());
+  ExplodedNodeSet Tmp;
+  const Expr* Ex = U->getSubExpr()->IgnoreParens();
+  Visit(Ex, Pred, Tmp);
+
+  for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+
+    const GRState* state = GetState(*I);
+    SVal loc = state->getSVal(Ex);
+
+    // Perform a load.
+    ExplodedNodeSet Tmp2;
+    evalLoad(Tmp2, Ex, *I, state, loc);
+
+    for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
+
+      state = GetState(*I2);
+      SVal V2_untested = state->getSVal(Ex);
+
+      // Propagate unknown and undefined values.
+      if (V2_untested.isUnknownOrUndef()) {
+        MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
+        continue;
+      }
+      DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
+
+      // Handle all other values.
+      BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add
+                                                     : BO_Sub;
+
+      // If the UnaryOperator has non-location type, use its type to create the
+      // constant value. If the UnaryOperator has location type, create the
+      // constant with int type and pointer width.
+      SVal RHS;
+
+      if (U->getType()->isAnyPointerType())
+        RHS = svalBuilder.makeIntValWithPtrWidth(1, false);
+      else
+        RHS = svalBuilder.makeIntVal(1, U->getType());
+
+      SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
+
+      // Conjure a new symbol if necessary to recover precision.
+      if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
+        DefinedOrUnknownSVal SymVal =
+          svalBuilder.getConjuredSymbolVal(NULL, Ex,
+                                      Builder->getCurrentBlockCount());
+        Result = SymVal;
+
+        // If the value is a location, ++/-- should always preserve
+        // non-nullness.  Check if the original value was non-null, and if so
+        // propagate that constraint.
+        if (Loc::IsLocType(U->getType())) {
+          DefinedOrUnknownSVal Constraint =
+            svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
+
+          if (!state->assume(Constraint, true)) {
+            // It isn't feasible for the original value to be null.
+            // Propagate this constraint.
+            Constraint = svalBuilder.evalEQ(state, SymVal,
+                                       svalBuilder.makeZeroVal(U->getType()));
+
+
+            state = state->assume(Constraint, false);
+            assert(state);
+          }
+        }
+      }
+
+      // Since the lvalue-to-rvalue conversion is explicit in the AST,
+      // we bind an l-value if the operator is prefix and an lvalue (in C++).
+      if (U->isPrefix() && U->isLValue())
+        state = state->BindExpr(U, loc);
+      else
+        state = state->BindExpr(U, V2);
+
+      // Perform the store.
+      evalStore(Dst, NULL, U, *I2, state, loc, Result);
+    }
+  }
+}
+
+void ExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred,
+                                ExplodedNodeSet& Dst) {
+  VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
+}
+
+void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A,
+                                             AsmStmt::const_outputs_iterator I,
+                                             AsmStmt::const_outputs_iterator E,
+                                     ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+  if (I == E) {
+    VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  Visit(*I, Pred, Tmp);
+  ++I;
+
+  for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
+    VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
+}
+
+void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A,
+                                            AsmStmt::const_inputs_iterator I,
+                                            AsmStmt::const_inputs_iterator E,
+                                            ExplodedNode* Pred,
+                                            ExplodedNodeSet& Dst) {
+  if (I == E) {
+
+    // We have processed both the inputs and the outputs.  All of the outputs
+    // should evaluate to Locs.  Nuke all of their values.
+
+    // FIXME: Some day in the future it would be nice to allow a "plug-in"
+    // which interprets the inline asm and stores proper results in the
+    // outputs.
+
+    const GRState* state = GetState(Pred);
+
+    for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
+                                   OE = A->end_outputs(); OI != OE; ++OI) {
+
+      SVal X = state->getSVal(*OI);
+      assert (!isa<NonLoc>(X));  // Should be an Lval, or unknown, undef.
+
+      if (isa<Loc>(X))
+        state = state->bindLoc(cast<Loc>(X), UnknownVal());
+    }
+
+    MakeNode(Dst, A, Pred, state);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  Visit(*I, Pred, Tmp);
+
+  ++I;
+
+  for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI)
+    VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
+}
+
+void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
+                                   ExplodedNodeSet &Dst) {
+  ExplodedNodeSet Src;
+  if (const Expr *RetE = RS->getRetValue()) {
+    // Record the returned expression in the state. It will be used in
+    // ProcessCallExit to bind the return value to the call expr.
+    {
+      static int Tag = 0;
+      SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
+      const GRState *state = GetState(Pred);
+      state = state->set<ReturnExpr>(RetE);
+      Pred = Builder->generateNode(RetE, state, Pred);
+    }
+    // We may get a NULL Pred because we generated a cached node.
+    if (Pred)
+      Visit(RetE, Pred, Src);
+  }
+  else {
+    Src.Add(Pred);
+  }
+
+  ExplodedNodeSet CheckedSet;
+  CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback);
+
+  for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+       I != E; ++I) {
+
+    assert(Builder && "StmtNodeBuilder must be defined.");
+
+    Pred = *I;
+    unsigned size = Dst.size();
+
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+    getTF().evalReturn(Dst, *this, *Builder, RS, Pred);
+
+    // Handle the case where no nodes where generated.
+    if (!Builder->BuildSinks && Dst.size() == size &&
+        !Builder->HasGeneratedNode)
+      MakeNode(Dst, RS, Pred, GetState(Pred));
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer functions: Binary operators.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
+                                       ExplodedNode* Pred,
+                                       ExplodedNodeSet& Dst) {
+  ExplodedNodeSet Tmp1;
+  Expr* LHS = B->getLHS()->IgnoreParens();
+  Expr* RHS = B->getRHS()->IgnoreParens();
+
+  Visit(LHS, Pred, Tmp1);
+  ExplodedNodeSet Tmp3;
+
+  for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
+    SVal LeftV = GetState(*I1)->getSVal(LHS);
+    ExplodedNodeSet Tmp2;
+    Visit(RHS, *I1, Tmp2);
+
+    ExplodedNodeSet CheckedSet;
+    CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback);
+
+    // With both the LHS and RHS evaluated, process the operation itself.
+
+    for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end();
+         I2 != E2; ++I2) {
+
+      const GRState *state = GetState(*I2);
+      SVal RightV = state->getSVal(RHS);
+
+      BinaryOperator::Opcode Op = B->getOpcode();
+
+      if (Op == BO_Assign) {
+        // EXPERIMENTAL: "Conjured" symbols.
+        // FIXME: Handle structs.
+        QualType T = RHS->getType();
+
+        if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV))
+        {
+          unsigned Count = Builder->getCurrentBlockCount();
+          RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count);
+        }
+
+        SVal ExprVal = B->isLValue() ? LeftV : RightV;
+
+        // Simulate the effects of a "store":  bind the value of the RHS
+        // to the L-Value represented by the LHS.
+        evalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
+        continue;
+      }
+
+      if (!B->isAssignmentOp()) {
+        // Process non-assignments except commas or short-circuited
+        // logical expressions (LAnd and LOr).
+        SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
+
+        if (Result.isUnknown()) {
+          MakeNode(Tmp3, B, *I2, state);
+          continue;
+        }
+
+        state = state->BindExpr(B, Result);
+
+        MakeNode(Tmp3, B, *I2, state);
+        continue;
+      }
+
+      assert (B->isCompoundAssignmentOp());
+
+      switch (Op) {
+        default:
+          assert(0 && "Invalid opcode for compound assignment.");
+        case BO_MulAssign: Op = BO_Mul; break;
+        case BO_DivAssign: Op = BO_Div; break;
+        case BO_RemAssign: Op = BO_Rem; break;
+        case BO_AddAssign: Op = BO_Add; break;
+        case BO_SubAssign: Op = BO_Sub; break;
+        case BO_ShlAssign: Op = BO_Shl; break;
+        case BO_ShrAssign: Op = BO_Shr; break;
+        case BO_AndAssign: Op = BO_And; break;
+        case BO_XorAssign: Op = BO_Xor; break;
+        case BO_OrAssign:  Op = BO_Or;  break;
+      }
+
+      // Perform a load (the LHS).  This performs the checks for
+      // null dereferences, and so on.
+      ExplodedNodeSet Tmp4;
+      SVal location = state->getSVal(LHS);
+      evalLoad(Tmp4, LHS, *I2, state, location);
+
+      for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4;
+           ++I4) {
+        state = GetState(*I4);
+        SVal V = state->getSVal(LHS);
+
+        // Get the computation type.
+        QualType CTy =
+          cast<CompoundAssignOperator>(B)->getComputationResultType();
+        CTy = getContext().getCanonicalType(CTy);
+
+        QualType CLHSTy =
+          cast<CompoundAssignOperator>(B)->getComputationLHSType();
+        CLHSTy = getContext().getCanonicalType(CLHSTy);
+
+        QualType LTy = getContext().getCanonicalType(LHS->getType());
+        QualType RTy = getContext().getCanonicalType(RHS->getType());
+
+        // Promote LHS.
+        V = svalBuilder.evalCast(V, CLHSTy, LTy);
+
+        // Compute the result of the operation.
+        SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
+                                      B->getType(), CTy);
+
+        // EXPERIMENTAL: "Conjured" symbols.
+        // FIXME: Handle structs.
+
+        SVal LHSVal;
+
+        if (Result.isUnknown() ||
+            !getConstraintManager().canReasonAbout(Result)) {
+
+          unsigned Count = Builder->getCurrentBlockCount();
+
+          // The symbolic value is actually for the type of the left-hand side
+          // expression, not the computation type, as this is the value the
+          // LValue on the LHS will bind to.
+          LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
+
+          // However, we need to convert the symbol to the computation type.
+          Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
+        }
+        else {
+          // The left-hand side may bind to a different value then the
+          // computation type.
+          LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
+        }
+
+        evalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result),
+                  location, LHSVal);
+      }
+    }
+  }
+
+  CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback);
+}
+
+//===----------------------------------------------------------------------===//
+// Checker registration/lookup.
+//===----------------------------------------------------------------------===//
+
+Checker *ExprEngine::lookupChecker(void *tag) const {
+  CheckerMap::const_iterator I = CheckerM.find(tag);
+  return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
+}
+
+//===----------------------------------------------------------------------===//
+// Visualization.
+//===----------------------------------------------------------------------===//
+
+#ifndef NDEBUG
+static ExprEngine* GraphPrintCheckerState;
+static SourceManager* GraphPrintSourceManager;
+
+namespace llvm {
+template<>
+struct DOTGraphTraits<ExplodedNode*> :
+  public DefaultDOTGraphTraits {
+
+  DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+  // FIXME: Since we do not cache error nodes in ExprEngine now, this does not
+  // work.
+  static std::string getNodeAttributes(const ExplodedNode* N, void*) {
+
+#if 0
+      // FIXME: Replace with a general scheme to tell if the node is
+      // an error node.
+    if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
+        GraphPrintCheckerState->isExplicitNullDeref(N) ||
+        GraphPrintCheckerState->isUndefDeref(N) ||
+        GraphPrintCheckerState->isUndefStore(N) ||
+        GraphPrintCheckerState->isUndefControlFlow(N) ||
+        GraphPrintCheckerState->isUndefResult(N) ||
+        GraphPrintCheckerState->isBadCall(N) ||
+        GraphPrintCheckerState->isUndefArg(N))
+      return "color=\"red\",style=\"filled\"";
+
+    if (GraphPrintCheckerState->isNoReturnCall(N))
+      return "color=\"blue\",style=\"filled\"";
+#endif
+    return "";
+  }
+
+  static std::string getNodeLabel(const ExplodedNode* N, void*){
+
+    std::string sbuf;
+    llvm::raw_string_ostream Out(sbuf);
+
+    // Program Location.
+    ProgramPoint Loc = N->getLocation();
+
+    switch (Loc.getKind()) {
+      case ProgramPoint::BlockEntranceKind:
+        Out << "Block Entrance: B"
+            << cast<BlockEntrance>(Loc).getBlock()->getBlockID();
+        break;
+
+      case ProgramPoint::BlockExitKind:
+        assert (false);
+        break;
+
+      case ProgramPoint::CallEnterKind:
+        Out << "CallEnter";
+        break;
+
+      case ProgramPoint::CallExitKind:
+        Out << "CallExit";
+        break;
+
+      default: {
+        if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
+          const Stmt* S = L->getStmt();
+          SourceLocation SLoc = S->getLocStart();
+
+          Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
+          LangOptions LO; // FIXME.
+          S->printPretty(Out, 0, PrintingPolicy(LO));
+
+          if (SLoc.isFileID()) {
+            Out << "\\lline="
+              << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
+              << " col="
+              << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc)
+              << "\\l";
+          }
+
+          if (isa<PreStmt>(Loc))
+            Out << "\\lPreStmt\\l;";
+          else if (isa<PostLoad>(Loc))
+            Out << "\\lPostLoad\\l;";
+          else if (isa<PostStore>(Loc))
+            Out << "\\lPostStore\\l";
+          else if (isa<PostLValue>(Loc))
+            Out << "\\lPostLValue\\l";
+
+#if 0
+            // FIXME: Replace with a general scheme to determine
+            // the name of the check.
+          if (GraphPrintCheckerState->isImplicitNullDeref(N))
+            Out << "\\|Implicit-Null Dereference.\\l";
+          else if (GraphPrintCheckerState->isExplicitNullDeref(N))
+            Out << "\\|Explicit-Null Dereference.\\l";
+          else if (GraphPrintCheckerState->isUndefDeref(N))
+            Out << "\\|Dereference of undefialied value.\\l";
+          else if (GraphPrintCheckerState->isUndefStore(N))
+            Out << "\\|Store to Undefined Loc.";
+          else if (GraphPrintCheckerState->isUndefResult(N))
+            Out << "\\|Result of operation is undefined.";
+          else if (GraphPrintCheckerState->isNoReturnCall(N))
+            Out << "\\|Call to function marked \"noreturn\".";
+          else if (GraphPrintCheckerState->isBadCall(N))
+            Out << "\\|Call to NULL/Undefined.";
+          else if (GraphPrintCheckerState->isUndefArg(N))
+            Out << "\\|Argument in call is undefined";
+#endif
+
+          break;
+        }
+
+        const BlockEdge& E = cast<BlockEdge>(Loc);
+        Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
+            << E.getDst()->getBlockID()  << ')';
+
+        if (const Stmt* T = E.getSrc()->getTerminator()) {
+
+          SourceLocation SLoc = T->getLocStart();
+
+          Out << "\\|Terminator: ";
+          LangOptions LO; // FIXME.
+          E.getSrc()->printTerminator(Out, LO);
+
+          if (SLoc.isFileID()) {
+            Out << "\\lline="
+              << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
+              << " col="
+              << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc);
+          }
+
+          if (isa<SwitchStmt>(T)) {
+            const Stmt* Label = E.getDst()->getLabel();
+
+            if (Label) {
+              if (const CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
+                Out << "\\lcase ";
+                LangOptions LO; // FIXME.
+                C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
+
+                if (const Stmt* RHS = C->getRHS()) {
+                  Out << " .. ";
+                  RHS->printPretty(Out, 0, PrintingPolicy(LO));
+                }
+
+                Out << ":";
+              }
+              else {
+                assert (isa<DefaultStmt>(Label));
+                Out << "\\ldefault:";
+              }
+            }
+            else
+              Out << "\\l(implicit) default:";
+          }
+          else if (isa<IndirectGotoStmt>(T)) {
+            // FIXME
+          }
+          else {
+            Out << "\\lCondition: ";
+            if (*E.getSrc()->succ_begin() == E.getDst())
+              Out << "true";
+            else
+              Out << "false";
+          }
+
+          Out << "\\l";
+        }
+
+#if 0
+          // FIXME: Replace with a general scheme to determine
+          // the name of the check.
+        if (GraphPrintCheckerState->isUndefControlFlow(N)) {
+          Out << "\\|Control-flow based on\\lUndefined value.\\l";
+        }
+#endif
+      }
+    }
+
+    const GRState *state = N->getState();
+    Out << "\\|StateID: " << (void*) state
+        << " NodeID: " << (void*) N << "\\|";
+    state->printDOT(Out, *N->getLocationContext()->getCFG());
+    Out << "\\l";
+    return Out.str();
+  }
+};
+} // end llvm namespace
+#endif
+
+#ifndef NDEBUG
+template <typename ITERATOR>
+ExplodedNode* GetGraphNode(ITERATOR I) { return *I; }
+
+template <> ExplodedNode*
+GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
+  (llvm::DenseMap<ExplodedNode*, Expr*>::iterator I) {
+  return I->first;
+}
+#endif
+
+void ExprEngine::ViewGraph(bool trim) {
+#ifndef NDEBUG
+  if (trim) {
+    std::vector<ExplodedNode*> Src;
+
+    // Flush any outstanding reports to make sure we cover all the nodes.
+    // This does not cause them to get displayed.
+    for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I)
+      const_cast<BugType*>(*I)->FlushReports(BR);
+
+    // Iterate through the reports and get their nodes.
+    for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) {
+      for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end();
+           I2!=E2; ++I2) {
+        const BugReportEquivClass& EQ = *I2;
+        const BugReport &R = **EQ.begin();
+        ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
+        if (N) Src.push_back(N);
+      }
+    }
+
+    ViewGraph(&Src[0], &Src[0]+Src.size());
+  }
+  else {
+    GraphPrintCheckerState = this;
+    GraphPrintSourceManager = &getContext().getSourceManager();
+
+    llvm::ViewGraph(*G.roots_begin(), "ExprEngine");
+
+    GraphPrintCheckerState = NULL;
+    GraphPrintSourceManager = NULL;
+  }
+#endif
+}
+
+void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
+#ifndef NDEBUG
+  GraphPrintCheckerState = this;
+  GraphPrintSourceManager = &getContext().getSourceManager();
+
+  std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
+
+  if (!TrimmedG.get())
+    llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
+  else
+    llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine");
+
+  GraphPrintCheckerState = NULL;
+  GraphPrintSourceManager = NULL;
+#endif
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp
new file mode 100644 (file)
index 0000000..52a3ace
--- /dev/null
@@ -0,0 +1,46 @@
+//=-- ExprEngineExperimentalChecks.h ------------------------------*- 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 functions to instantiate and register experimental
+//  checks in ExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "ExprEngineExperimentalChecks.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+
+using namespace clang;
+using namespace ento;
+
+void ento::RegisterExperimentalChecks(ExprEngine &Eng) {
+  // These are checks that never belong as internal checks
+  // within ExprEngine.
+  RegisterCStringChecker(Eng);
+  RegisterChrootChecker(Eng);
+  RegisterMallocChecker(Eng);
+  RegisterPthreadLockChecker(Eng);
+  RegisterStreamChecker(Eng);
+  RegisterUnreachableCodeChecker(Eng);
+}
+
+void ento::RegisterExperimentalInternalChecks(ExprEngine &Eng) {
+  // These are internal checks that should eventually migrate to
+  // RegisterInternalChecks() once they have been further tested.
+  
+  // Note that this must be registered after ReturnStackAddresEngsChecker.
+  RegisterReturnPointerRangeChecker(Eng);
+  
+  RegisterArrayBoundChecker(Eng);
+  RegisterCastSizeChecker(Eng);
+  RegisterCastToStructChecker(Eng);
+  RegisterFixedAddressChecker(Eng);
+  RegisterPointerArithChecker(Eng);
+  RegisterPointerSubChecker(Eng);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h b/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h
new file mode 100644 (file)
index 0000000..f8359d1
--- /dev/null
@@ -0,0 +1,37 @@
+//=-- ExprEngineExperimentalChecks.h ------------------------------*- 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 functions to instantiate and register experimental
+//  checks in ExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS
+#define LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS
+
+namespace clang {
+
+namespace ento {
+
+class ExprEngine;
+
+void RegisterAnalyzerStatsChecker(ExprEngine &Eng);
+void RegisterChrootChecker(ExprEngine &Eng);
+void RegisterCStringChecker(ExprEngine &Eng);
+void RegisterIdempotentOperationChecker(ExprEngine &Eng);
+void RegisterMallocChecker(ExprEngine &Eng);
+void RegisterPthreadLockChecker(ExprEngine &Eng);
+void RegisterStreamChecker(ExprEngine &Eng);
+void RegisterUnreachableCodeChecker(ExprEngine &Eng);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h b/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h
new file mode 100644 (file)
index 0000000..f67371d
--- /dev/null
@@ -0,0 +1,59 @@
+//=-- ExprEngineInternalChecks.h- Builtin ExprEngine Checks -----*- 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 functions to instantiate and register the "built-in"
+//  checks in ExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS
+#define LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS
+
+namespace clang {
+
+namespace ento {
+
+class ExprEngine;
+
+// Foundational checks that handle basic semantics.
+void RegisterAdjustedReturnValueChecker(ExprEngine &Eng);
+void RegisterArrayBoundChecker(ExprEngine &Eng);
+void RegisterArrayBoundCheckerV2(ExprEngine &Eng);
+void RegisterAttrNonNullChecker(ExprEngine &Eng);
+void RegisterBuiltinFunctionChecker(ExprEngine &Eng);
+void RegisterCallAndMessageChecker(ExprEngine &Eng);
+void RegisterCastToStructChecker(ExprEngine &Eng);
+void RegisterCastSizeChecker(ExprEngine &Eng);
+void RegisterDereferenceChecker(ExprEngine &Eng);
+void RegisterDivZeroChecker(ExprEngine &Eng);
+void RegisterFixedAddressChecker(ExprEngine &Eng);
+void RegisterNoReturnFunctionChecker(ExprEngine &Eng);
+void RegisterObjCAtSyncChecker(ExprEngine &Eng);
+void RegisterPointerArithChecker(ExprEngine &Eng);
+void RegisterPointerSubChecker(ExprEngine &Eng);
+void RegisterReturnPointerRangeChecker(ExprEngine &Eng);
+void RegisterReturnUndefChecker(ExprEngine &Eng);
+void RegisterStackAddrLeakChecker(ExprEngine &Eng);
+void RegisterUndefBranchChecker(ExprEngine &Eng);
+void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng);
+void RegisterUndefResultChecker(ExprEngine &Eng);
+void RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng);
+void RegisterUndefinedAssignmentChecker(ExprEngine &Eng);
+void RegisterVLASizeChecker(ExprEngine &Eng);
+
+// API checks.
+void RegisterMacOSXAPIChecker(ExprEngine &Eng);
+void RegisterOSAtomicChecker(ExprEngine &Eng);
+void RegisterUnixAPIChecker(ExprEngine &Eng);
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp
new file mode 100644 (file)
index 0000000..77e9876
--- /dev/null
@@ -0,0 +1,72 @@
+//=== FixedAddressChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines FixedAddressChecker, a builtin checker that checks for
+// assignment of a fixed address to a pointer.
+// This check corresponds to CWE-587.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class FixedAddressChecker 
+  : public CheckerVisitor<FixedAddressChecker> {
+  BuiltinBug *BT;
+public:
+  FixedAddressChecker() : BT(0) {}
+  static void *getTag();
+  void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *FixedAddressChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
+                                                 const BinaryOperator *B) {
+  // Using a fixed address is not portable because that address will probably
+  // not be valid in all environments or platforms.
+
+  if (B->getOpcode() != BO_Assign)
+    return;
+
+  QualType T = B->getType();
+  if (!T->isPointerType())
+    return;
+
+  const GRState *state = C.getState();
+
+  SVal RV = state->getSVal(B->getRHS());
+
+  if (!RV.isConstant() || RV.isZeroConstant())
+    return;
+
+  if (ExplodedNode *N = C.generateNode()) {
+    if (!BT)
+      BT = new BuiltinBug("Use fixed address", 
+                          "Using a fixed address is not portable because that "
+                          "address will probably not be valid in all "
+                          "environments or platforms.");
+    RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+    R->addRange(B->getRHS()->getSourceRange());
+    C.EmitReport(R);
+  }
+}
+
+void ento::RegisterFixedAddressChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new FixedAddressChecker());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp
new file mode 100644 (file)
index 0000000..b0e8e5d
--- /dev/null
@@ -0,0 +1,22 @@
+//===--- FrontendActions.cpp ----------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/FrontendActions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/StaticAnalyzer/AnalysisConsumer.h"
+using namespace clang;
+using namespace ento;
+
+ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
+                                               llvm::StringRef InFile) {
+  return CreateAnalysisConsumer(CI.getPreprocessor(),
+                                CI.getFrontendOpts().OutputFile,
+                                CI.getAnalyzerOpts());
+}
+
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp
new file mode 100644 (file)
index 0000000..435d3d4
--- /dev/null
@@ -0,0 +1,834 @@
+//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- 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 a set of path-sensitive checks for idempotent and/or
+// tautological operations. Each potential operation is checked along all paths
+// to see if every path results in a pointless operation.
+//                 +-------------------------------------------+
+//                 |Table of idempotent/tautological operations|
+//                 +-------------------------------------------+
+//+--------------------------------------------------------------------------+
+//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op x |
+//+--------------------------------------------------------------------------+
+//  +, +=   |        |        |        |   x    |   x    |         |
+//  -, -=   |        |        |        |   x    |   -x   |         |
+//  *, *=   |        |   x    |   x    |   0    |   0    |         |
+//  /, /=   |   1    |   x    |        |  N/A   |   0    |         |
+//  &, &=   |   x    |        |        |   0    |   0    |   x     |    x
+//  |, |=   |   x    |        |        |   x    |   x    |   ~0    |    ~0
+//  ^, ^=   |   0    |        |        |   x    |   x    |         |
+//  <<, <<= |        |        |        |   x    |   0    |         |
+//  >>, >>= |        |        |        |   x    |   0    |         |
+//  ||      |   1    |   1    |   1    |   x    |   x    |   1     |    1
+//  &&      |   1    |   x    |   x    |   0    |   0    |   x     |    x
+//  =       |   x    |        |        |        |        |         |
+//  ==      |   1    |        |        |        |        |         |
+//  >=      |   1    |        |        |        |        |         |
+//  <=      |   1    |        |        |        |        |         |
+//  >       |   0    |        |        |        |        |         |
+//  <       |   0    |        |        |        |        |         |
+//  !=      |   0    |        |        |        |        |         |
+//===----------------------------------------------------------------------===//
+//
+// Things TODO:
+// - Improved error messages
+// - Handle mixed assumptions (which assumptions can belong together?)
+// - Finer grained false positive control (levels)
+// - Handling ~0 values
+
+#include "ExprEngineExperimentalChecks.h"
+#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <deque>
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class IdempotentOperationChecker
+  : public CheckerVisitor<IdempotentOperationChecker> {
+public:
+  static void *getTag();
+  void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+  void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+  void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng);
+
+private:
+  // Our assumption about a particular operation.
+  enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0,
+      RHSis0 };
+
+  void UpdateAssumption(Assumption &A, const Assumption &New);
+
+  // False positive reduction methods
+  static bool isSelfAssign(const Expr *LHS, const Expr *RHS);
+  static bool isUnused(const Expr *E, AnalysisContext *AC);
+  static bool isTruncationExtensionAssignment(const Expr *LHS,
+                                              const Expr *RHS);
+  bool PathWasCompletelyAnalyzed(const CFG *C,
+                                 const CFGBlock *CB,
+                                 const CFGStmtMap *CBM,
+                                 const CoreEngine &CE);
+  static bool CanVary(const Expr *Ex,
+                      AnalysisContext *AC);
+  static bool isConstantOrPseudoConstant(const DeclRefExpr *DR,
+                                         AnalysisContext *AC);
+  static bool containsNonLocalVarDecl(const Stmt *S);
+  const ExplodedNodeSet getLastRelevantNodes(const CFGBlock *Begin,
+                                             const ExplodedNode *N);
+
+  // Hash table and related data structures
+  struct BinaryOperatorData {
+    BinaryOperatorData() : assumption(Possible), analysisContext(0) {}
+
+    Assumption assumption;
+    AnalysisContext *analysisContext;
+    ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a
+                                   // BinaryOperator
+  };
+  typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData>
+      AssumptionMap;
+  AssumptionMap hash;
+
+  // A class that performs reachability queries for CFGBlocks. Several internal
+  // checks in this checker require reachability information. The requests all
+  // tend to have a common destination, so we lazily do a predecessor search
+  // from the destination node and cache the results to prevent work
+  // duplication.
+  class CFGReachabilityAnalysis {
+    typedef llvm::SmallSet<unsigned, 32> ReachableSet;
+    typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
+    ReachableSet analyzed;
+    ReachableMap reachable;
+  public:
+    inline bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
+  private:
+    void MapReachability(const CFGBlock *Dst);
+  };
+  CFGReachabilityAnalysis CRA;
+};
+}
+
+void *IdempotentOperationChecker::getTag() {
+  static int x = 0;
+  return &x;
+}
+
+void ento::RegisterIdempotentOperationChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new IdempotentOperationChecker());
+}
+
+void IdempotentOperationChecker::PreVisitBinaryOperator(
+                                                      CheckerContext &C,
+                                                      const BinaryOperator *B) {
+  // Find or create an entry in the hash for this BinaryOperator instance.
+  // If we haven't done a lookup before, it will get default initialized to
+  // 'Possible'. At this stage we do not store the ExplodedNode, as it has not
+  // been created yet.
+  BinaryOperatorData &Data = hash[B];
+  Assumption &A = Data.assumption;
+  AnalysisContext *AC = C.getCurrentAnalysisContext();
+  Data.analysisContext = AC;
+
+  // If we already have visited this node on a path that does not contain an
+  // idempotent operation, return immediately.
+  if (A == Impossible)
+    return;
+
+  // Retrieve both sides of the operator and determine if they can vary (which
+  // may mean this is a false positive.
+  const Expr *LHS = B->getLHS();
+  const Expr *RHS = B->getRHS();
+
+  // At this stage we can calculate whether each side contains a false positive
+  // that applies to all operators. We only need to calculate this the first
+  // time.
+  bool LHSContainsFalsePositive = false, RHSContainsFalsePositive = false;
+  if (A == Possible) {
+    // An expression contains a false positive if it can't vary, or if it
+    // contains a known false positive VarDecl.
+    LHSContainsFalsePositive = !CanVary(LHS, AC)
+        || containsNonLocalVarDecl(LHS);
+    RHSContainsFalsePositive = !CanVary(RHS, AC)
+        || containsNonLocalVarDecl(RHS);
+  }
+
+  const GRState *state = C.getState();
+
+  SVal LHSVal = state->getSVal(LHS);
+  SVal RHSVal = state->getSVal(RHS);
+
+  // If either value is unknown, we can't be 100% sure of all paths.
+  if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
+    A = Impossible;
+    return;
+  }
+  BinaryOperator::Opcode Op = B->getOpcode();
+
+  // Dereference the LHS SVal if this is an assign operation
+  switch (Op) {
+  default:
+    break;
+
+  // Fall through intentional
+  case BO_AddAssign:
+  case BO_SubAssign:
+  case BO_MulAssign:
+  case BO_DivAssign:
+  case BO_AndAssign:
+  case BO_OrAssign:
+  case BO_XorAssign:
+  case BO_ShlAssign:
+  case BO_ShrAssign:
+  case BO_Assign:
+  // Assign statements have one extra level of indirection
+    if (!isa<Loc>(LHSVal)) {
+      A = Impossible;
+      return;
+    }
+    LHSVal = state->getSVal(cast<Loc>(LHSVal), LHS->getType());
+  }
+
+
+  // We now check for various cases which result in an idempotent operation.
+
+  // x op x
+  switch (Op) {
+  default:
+    break; // We don't care about any other operators.
+
+  // Fall through intentional
+  case BO_Assign:
+    // x Assign x can be used to silence unused variable warnings intentionally.
+    // If this is a self assignment and the variable is referenced elsewhere,
+    // and the assignment is not a truncation or extension, then it is a false
+    // positive.
+    if (isSelfAssign(LHS, RHS)) {
+      if (!isUnused(LHS, AC) && !isTruncationExtensionAssignment(LHS, RHS)) {
+        UpdateAssumption(A, Equal);
+        return;
+      }
+      else {
+        A = Impossible;
+        return;
+      }
+    }
+
+  case BO_SubAssign:
+  case BO_DivAssign:
+  case BO_AndAssign:
+  case BO_OrAssign:
+  case BO_XorAssign:
+  case BO_Sub:
+  case BO_Div:
+  case BO_And:
+  case BO_Or:
+  case BO_Xor:
+  case BO_LOr:
+  case BO_LAnd:
+  case BO_EQ:
+  case BO_NE:
+    if (LHSVal != RHSVal || LHSContainsFalsePositive
+        || RHSContainsFalsePositive)
+      break;
+    UpdateAssumption(A, Equal);
+    return;
+  }
+
+  // x op 1
+  switch (Op) {
+   default:
+     break; // We don't care about any other operators.
+
+   // Fall through intentional
+   case BO_MulAssign:
+   case BO_DivAssign:
+   case BO_Mul:
+   case BO_Div:
+   case BO_LOr:
+   case BO_LAnd:
+     if (!RHSVal.isConstant(1) || RHSContainsFalsePositive)
+       break;
+     UpdateAssumption(A, RHSis1);
+     return;
+  }
+
+  // 1 op x
+  switch (Op) {
+  default:
+    break; // We don't care about any other operators.
+
+  // Fall through intentional
+  case BO_MulAssign:
+  case BO_Mul:
+  case BO_LOr:
+  case BO_LAnd:
+    if (!LHSVal.isConstant(1) || LHSContainsFalsePositive)
+      break;
+    UpdateAssumption(A, LHSis1);
+    return;
+  }
+
+  // x op 0
+  switch (Op) {
+  default:
+    break; // We don't care about any other operators.
+
+  // Fall through intentional
+  case BO_AddAssign:
+  case BO_SubAssign:
+  case BO_MulAssign:
+  case BO_AndAssign:
+  case BO_OrAssign:
+  case BO_XorAssign:
+  case BO_Add:
+  case BO_Sub:
+  case BO_Mul:
+  case BO_And:
+  case BO_Or:
+  case BO_Xor:
+  case BO_Shl:
+  case BO_Shr:
+  case BO_LOr:
+  case BO_LAnd:
+    if (!RHSVal.isConstant(0) || RHSContainsFalsePositive)
+      break;
+    UpdateAssumption(A, RHSis0);
+    return;
+  }
+
+  // 0 op x
+  switch (Op) {
+  default:
+    break; // We don't care about any other operators.
+
+  // Fall through intentional
+  //case BO_AddAssign: // Common false positive
+  case BO_SubAssign: // Check only if unsigned
+  case BO_MulAssign:
+  case BO_DivAssign:
+  case BO_AndAssign:
+  //case BO_OrAssign: // Common false positive
+  //case BO_XorAssign: // Common false positive
+  case BO_ShlAssign:
+  case BO_ShrAssign:
+  case BO_Add:
+  case BO_Sub:
+  case BO_Mul:
+  case BO_Div:
+  case BO_And:
+  case BO_Or:
+  case BO_Xor:
+  case BO_Shl:
+  case BO_Shr:
+  case BO_LOr:
+  case BO_LAnd:
+    if (!LHSVal.isConstant(0) || LHSContainsFalsePositive)
+      break;
+    UpdateAssumption(A, LHSis0);
+    return;
+  }
+
+  // If we get to this point, there has been a valid use of this operation.
+  A = Impossible;
+}
+
+// At the post visit stage, the predecessor ExplodedNode will be the
+// BinaryOperator that was just created. We use this hook to collect the
+// ExplodedNode.
+void IdempotentOperationChecker::PostVisitBinaryOperator(
+                                                      CheckerContext &C,
+                                                      const BinaryOperator *B) {
+  // Add the ExplodedNode we just visited
+  BinaryOperatorData &Data = hash[B];
+  assert(isa<BinaryOperator>(cast<StmtPoint>(C.getPredecessor()
+                                             ->getLocation()).getStmt()));
+  Data.explodedNodes.Add(C.getPredecessor());
+}
+
+void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
+                                                  BugReporter &BR,
+                                                  ExprEngine &Eng) {
+  BugType *BT = new BugType("Idempotent operation", "Dead code");
+  // Iterate over the hash to see if we have any paths with definite
+  // idempotent operations.
+  for (AssumptionMap::const_iterator i = hash.begin(); i != hash.end(); ++i) {
+    // Unpack the hash contents
+    const BinaryOperatorData &Data = i->second;
+    const Assumption &A = Data.assumption;
+    AnalysisContext *AC = Data.analysisContext;
+    const ExplodedNodeSet &ES = Data.explodedNodes;
+
+    const BinaryOperator *B = i->first;
+
+    if (A == Impossible)
+      continue;
+
+    // If the analyzer did not finish, check to see if we can still emit this
+    // warning
+    if (Eng.hasWorkRemaining()) {
+      const CFGStmtMap *CBM = CFGStmtMap::Build(AC->getCFG(),
+                                                &AC->getParentMap());
+
+      // If we can trace back
+      if (!PathWasCompletelyAnalyzed(AC->getCFG(),
+                                     CBM->getBlock(B), CBM,
+                                     Eng.getCoreEngine()))
+        continue;
+
+      delete CBM;
+    }
+
+    // Select the error message and SourceRanges to report.
+    llvm::SmallString<128> buf;
+    llvm::raw_svector_ostream os(buf);
+    bool LHSRelevant = false, RHSRelevant = false;
+    switch (A) {
+    case Equal:
+      LHSRelevant = true;
+      RHSRelevant = true;
+      if (B->getOpcode() == BO_Assign)
+        os << "Assigned value is always the same as the existing value";
+      else
+        os << "Both operands to '" << B->getOpcodeStr()
+           << "' always have the same value";
+      break;
+    case LHSis1:
+      LHSRelevant = true;
+      os << "The left operand to '" << B->getOpcodeStr() << "' is always 1";
+      break;
+    case RHSis1:
+      RHSRelevant = true;
+      os << "The right operand to '" << B->getOpcodeStr() << "' is always 1";
+      break;
+    case LHSis0:
+      LHSRelevant = true;
+      os << "The left operand to '" << B->getOpcodeStr() << "' is always 0";
+      break;
+    case RHSis0:
+      RHSRelevant = true;
+      os << "The right operand to '" << B->getOpcodeStr() << "' is always 0";
+      break;
+    case Possible:
+      llvm_unreachable("Operation was never marked with an assumption");
+    case Impossible:
+      llvm_unreachable(0);
+    }
+
+    // Add a report for each ExplodedNode
+    for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) {
+      EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), *I);
+
+      // Add source ranges and visitor hooks
+      if (LHSRelevant) {
+        const Expr *LHS = i->first->getLHS();
+        report->addRange(LHS->getSourceRange());
+        report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, LHS);
+      }
+      if (RHSRelevant) {
+        const Expr *RHS = i->first->getRHS();
+        report->addRange(i->first->getRHS()->getSourceRange());
+        report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, RHS);
+      }
+
+      BR.EmitReport(report);
+    }
+  }
+}
+
+// Updates the current assumption given the new assumption
+inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A,
+                                                        const Assumption &New) {
+// If the assumption is the same, there is nothing to do
+  if (A == New)
+    return;
+
+  switch (A) {
+  // If we don't currently have an assumption, set it
+  case Possible:
+    A = New;
+    return;
+
+  // If we have determined that a valid state happened, ignore the new
+  // assumption.
+  case Impossible:
+    return;
+
+  // Any other case means that we had a different assumption last time. We don't
+  // currently support mixing assumptions for diagnostic reasons, so we set
+  // our assumption to be impossible.
+  default:
+    A = Impossible;
+    return;
+  }
+}
+
+// Check for a statement where a variable is self assigned to possibly avoid an
+// unused variable warning.
+bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS) {
+  LHS = LHS->IgnoreParenCasts();
+  RHS = RHS->IgnoreParenCasts();
+
+  const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS);
+  if (!LHS_DR)
+    return false;
+
+  const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
+  if (!VD)
+    return false;
+
+  const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS);
+  if (!RHS_DR)
+    return false;
+
+  if (VD != RHS_DR->getDecl())
+    return false;
+
+  return true;
+}
+
+// Returns true if the Expr points to a VarDecl that is not read anywhere
+// outside of self-assignments.
+bool IdempotentOperationChecker::isUnused(const Expr *E,
+                                          AnalysisContext *AC) {
+  if (!E)
+    return false;
+
+  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+  if (!DR)
+    return false;
+
+  const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+  if (!VD)
+    return false;
+
+  if (AC->getPseudoConstantAnalysis()->wasReferenced(VD))
+    return false;
+
+  return true;
+}
+
+// Check for self casts truncating/extending a variable
+bool IdempotentOperationChecker::isTruncationExtensionAssignment(
+                                                              const Expr *LHS,
+                                                              const Expr *RHS) {
+
+  const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts());
+  if (!LHS_DR)
+    return false;
+
+  const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
+  if (!VD)
+    return false;
+
+  const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts());
+  if (!RHS_DR)
+    return false;
+
+  if (VD != RHS_DR->getDecl())
+     return false;
+
+  return dyn_cast<DeclRefExpr>(RHS->IgnoreParenLValueCasts()) == NULL;
+}
+
+// Returns false if a path to this block was not completely analyzed, or true
+// otherwise.
+bool IdempotentOperationChecker::PathWasCompletelyAnalyzed(
+                                                       const CFG *C,
+                                                       const CFGBlock *CB,
+                                                       const CFGStmtMap *CBM,
+                                                       const CoreEngine &CE) {
+  // Test for reachability from any aborted blocks to this block
+  typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
+  for (AbortedIterator I = CE.blocks_aborted_begin(),
+      E = CE.blocks_aborted_end(); I != E; ++I) {
+    const BlockEdge &BE =  I->first;
+
+    // The destination block on the BlockEdge is the first block that was not
+    // analyzed. If we can reach this block from the aborted block, then this
+    // block was not completely analyzed.
+    if (CRA.isReachable(BE.getDst(), CB))
+      return false;
+  }
+  
+  // For the items still on the worklist, see if they are in blocks that
+  // can eventually reach 'CB'.
+  class VisitWL : public WorkList::Visitor {
+    const CFGStmtMap *CBM;
+    const CFGBlock *TargetBlock;
+    CFGReachabilityAnalysis &CRA;
+  public:
+    VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock,
+            CFGReachabilityAnalysis &cra)
+      : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {}
+    virtual bool Visit(const WorkListUnit &U) {
+      ProgramPoint P = U.getNode()->getLocation();
+      const CFGBlock *B = 0;
+      if (StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+        B = CBM->getBlock(SP->getStmt());
+      }
+      else if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+        B = BE->getDst();
+      }
+      else if (BlockEntrance *BEnt = dyn_cast<BlockEntrance>(&P)) {
+        B = BEnt->getBlock();
+      }
+      else if (BlockExit *BExit = dyn_cast<BlockExit>(&P)) {
+        B = BExit->getBlock();
+      }
+      if (!B)
+        return true;
+      
+      return CRA.isReachable(B, TargetBlock);
+    }
+  };
+  VisitWL visitWL(CBM, CB, CRA);
+  // Were there any items in the worklist that could potentially reach
+  // this block?
+  if (CE.getWorkList()->VisitItemsInWorkList(visitWL))
+    return false;
+
+  // Verify that this block is reachable from the entry block
+  if (!CRA.isReachable(&C->getEntry(), CB))
+    return false;
+
+  // If we get to this point, there is no connection to the entry block or an
+  // aborted block. This path is unreachable and we can report the error.
+  return true;
+}
+
+// Recursive function that determines whether an expression contains any element
+// that varies. This could be due to a compile-time constant like sizeof. An
+// expression may also involve a variable that behaves like a constant. The
+// function returns true if the expression varies, and false otherwise.
+bool IdempotentOperationChecker::CanVary(const Expr *Ex,
+                                         AnalysisContext *AC) {
+  // Parentheses and casts are irrelevant here
+  Ex = Ex->IgnoreParenCasts();
+
+  if (Ex->getLocStart().isMacroID())
+    return false;
+
+  switch (Ex->getStmtClass()) {
+  // Trivially true cases
+  case Stmt::ArraySubscriptExprClass:
+  case Stmt::MemberExprClass:
+  case Stmt::StmtExprClass:
+  case Stmt::CallExprClass:
+  case Stmt::VAArgExprClass:
+  case Stmt::ShuffleVectorExprClass:
+    return true;
+  default:
+    return true;
+
+  // Trivially false cases
+  case Stmt::IntegerLiteralClass:
+  case Stmt::CharacterLiteralClass:
+  case Stmt::FloatingLiteralClass:
+  case Stmt::PredefinedExprClass:
+  case Stmt::ImaginaryLiteralClass:
+  case Stmt::StringLiteralClass:
+  case Stmt::OffsetOfExprClass:
+  case Stmt::CompoundLiteralExprClass:
+  case Stmt::AddrLabelExprClass:
+  case Stmt::BinaryTypeTraitExprClass:
+  case Stmt::GNUNullExprClass:
+  case Stmt::InitListExprClass:
+  case Stmt::DesignatedInitExprClass:
+  case Stmt::BlockExprClass:
+  case Stmt::BlockDeclRefExprClass:
+    return false;
+
+  // Cases requiring custom logic
+  case Stmt::SizeOfAlignOfExprClass: {
+    const SizeOfAlignOfExpr *SE = cast<const SizeOfAlignOfExpr>(Ex);
+    if (!SE->isSizeOf())
+      return false;
+    return SE->getTypeOfArgument()->isVariableArrayType();
+  }
+  case Stmt::DeclRefExprClass:
+    // Check for constants/pseudoconstants
+    return !isConstantOrPseudoConstant(cast<DeclRefExpr>(Ex), AC);
+
+  // The next cases require recursion for subexpressions
+  case Stmt::BinaryOperatorClass: {
+    const BinaryOperator *B = cast<const BinaryOperator>(Ex);
+
+    // Exclude cases involving pointer arithmetic.  These are usually
+    // false positives.
+    if (B->getOpcode() == BO_Sub || B->getOpcode() == BO_Add)
+      if (B->getLHS()->getType()->getAs<PointerType>())
+        return false;
+
+    return CanVary(B->getRHS(), AC)
+        || CanVary(B->getLHS(), AC);
+   }
+  case Stmt::UnaryOperatorClass: {
+    const UnaryOperator *U = cast<const UnaryOperator>(Ex);
+    // Handle trivial case first
+    switch (U->getOpcode()) {
+    case UO_Extension:
+      return false;
+    default:
+      return CanVary(U->getSubExpr(), AC);
+    }
+  }
+  case Stmt::ChooseExprClass:
+    return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr(
+        AC->getASTContext()), AC);
+  case Stmt::ConditionalOperatorClass:
+    return CanVary(cast<const ConditionalOperator>(Ex)->getCond(), AC);
+  }
+}
+
+// Returns true if a DeclRefExpr is or behaves like a constant.
+bool IdempotentOperationChecker::isConstantOrPseudoConstant(
+                                                          const DeclRefExpr *DR,
+                                                          AnalysisContext *AC) {
+  // Check if the type of the Decl is const-qualified
+  if (DR->getType().isConstQualified())
+    return true;
+
+  // Check for an enum
+  if (isa<EnumConstantDecl>(DR->getDecl()))
+    return true;
+
+  const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+  if (!VD)
+    return true;
+
+  // Check if the Decl behaves like a constant. This check also takes care of
+  // static variables, which can only change between function calls if they are
+  // modified in the AST.
+  PseudoConstantAnalysis *PCA = AC->getPseudoConstantAnalysis();
+  if (PCA->isPseudoConstant(VD))
+    return true;
+
+  return false;
+}
+
+// Recursively find any substatements containing VarDecl's with storage other
+// than local
+bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) {
+  const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
+
+  if (DR)
+    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+      if (!VD->hasLocalStorage())
+        return true;
+
+  for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
+      ++I)
+    if (const Stmt *child = *I)
+      if (containsNonLocalVarDecl(child))
+        return true;
+
+  return false;
+}
+
+// Returns the successor nodes of N whose CFGBlocks cannot reach N's CFGBlock.
+// This effectively gives us a set of points in the ExplodedGraph where
+// subsequent execution could not affect the idempotent operation on this path.
+// This is useful for displaying paths after the point of the error, providing
+// an example of how this idempotent operation cannot change.
+const ExplodedNodeSet IdempotentOperationChecker::getLastRelevantNodes(
+    const CFGBlock *Begin, const ExplodedNode *N) {
+  std::deque<const ExplodedNode *> WorkList;
+  llvm::SmallPtrSet<const ExplodedNode *, 32> Visited;
+  ExplodedNodeSet Result;
+
+  WorkList.push_back(N);
+
+  while (!WorkList.empty()) {
+    const ExplodedNode *Head = WorkList.front();
+    WorkList.pop_front();
+    Visited.insert(Head);
+
+    const ProgramPoint &PP = Head->getLocation();
+    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) {
+      // Get the CFGBlock and test the reachability
+      const CFGBlock *CB = BE->getBlock();
+
+      // If we cannot reach the beginning CFGBlock from this block, then we are
+      // finished
+      if (!CRA.isReachable(CB, Begin)) {
+        Result.Add(const_cast<ExplodedNode *>(Head));
+        continue;
+      }
+    }
+
+    // Add unvisited children to the worklist
+    for (ExplodedNode::const_succ_iterator I = Head->succ_begin(),
+        E = Head->succ_end(); I != E; ++I)
+      if (!Visited.count(*I))
+        WorkList.push_back(*I);
+  }
+
+  // Return the ExplodedNodes that were found
+  return Result;
+}
+
+bool IdempotentOperationChecker::CFGReachabilityAnalysis::isReachable(
+                                                          const CFGBlock *Src,
+                                                          const CFGBlock *Dst) {
+  const unsigned DstBlockID = Dst->getBlockID();
+
+  // If we haven't analyzed the destination node, run the analysis now
+  if (!analyzed.count(DstBlockID)) {
+    MapReachability(Dst);
+    analyzed.insert(DstBlockID);
+  }
+
+  // Return the cached result
+  return reachable[DstBlockID].count(Src->getBlockID());
+}
+
+// Maps reachability to a common node by walking the predecessors of the
+// destination node.
+void IdempotentOperationChecker::CFGReachabilityAnalysis::MapReachability(
+                                                          const CFGBlock *Dst) {
+  std::deque<const CFGBlock *> WorkList;
+  // Maintain a visited list to ensure we don't get stuck on cycles
+  llvm::SmallSet<unsigned, 32> Visited;
+  ReachableSet &DstReachability = reachable[Dst->getBlockID()];
+
+  // Start searching from the destination node, since we commonly will perform
+  // multiple queries relating to a destination node.
+  WorkList.push_back(Dst);
+
+  bool firstRun = true;
+  while (!WorkList.empty()) {
+    const CFGBlock *Head = WorkList.front();
+    WorkList.pop_front();
+    Visited.insert(Head->getBlockID());
+
+    // Update reachability information for this node -> Dst
+    if (!firstRun)
+      // Don't insert Dst -> Dst unless it was a predecessor of itself
+      DstReachability.insert(Head->getBlockID());
+    else
+      firstRun = false;
+
+    // Add the predecessors to the worklist unless we have already visited them
+    for (CFGBlock::const_pred_iterator I = Head->pred_begin();
+        I != Head->pred_end(); ++I)
+      if (!Visited.count((*I)->getBlockID()))
+        WorkList.push_back(*I);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp
new file mode 100644 (file)
index 0000000..eefad95
--- /dev/null
@@ -0,0 +1,313 @@
+//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines LLVMConventionsChecker, a bunch of small little checks
+// for checking specific coding conventions in the LLVM/Clang codebase.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include <string>
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Generic type checking routines.
+//===----------------------------------------------------------------------===//
+
+static bool IsLLVMStringRef(QualType T) {
+  const RecordType *RT = T->getAs<RecordType>();
+  if (!RT)
+    return false;
+
+  return llvm::StringRef(QualType(RT, 0).getAsString()) ==
+          "class llvm::StringRef";
+}
+
+/// Check whether the declaration is semantically inside the top-level
+/// namespace named by ns.
+static bool InNamespace(const Decl *D, llvm::StringRef NS) {
+  const DeclContext *DC = D->getDeclContext();
+  const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
+  if (!ND)
+    return false;
+  const IdentifierInfo *II = ND->getIdentifier();
+  if (!II || !II->getName().equals(NS))
+    return false;
+  DC = ND->getDeclContext();
+  return isa<TranslationUnitDecl>(DC);
+}
+
+static bool IsStdString(QualType T) {
+  if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
+    T = QT->getNamedType();
+
+  const TypedefType *TT = T->getAs<TypedefType>();
+  if (!TT)
+    return false;
+
+  const TypedefDecl *TD = TT->getDecl();
+
+  if (!InNamespace(TD, "std"))
+    return false;
+
+  return TD->getName() == "string";
+}
+
+static bool IsClangType(const RecordDecl *RD) {
+  return RD->getName() == "Type" && InNamespace(RD, "clang");
+}
+
+static bool IsClangDecl(const RecordDecl *RD) {
+  return RD->getName() == "Decl" && InNamespace(RD, "clang");
+}
+
+static bool IsClangStmt(const RecordDecl *RD) {
+  return RD->getName() == "Stmt" && InNamespace(RD, "clang");
+}
+
+static bool IsClangAttr(const RecordDecl *RD) {
+  return RD->getName() == "Attr" && InNamespace(RD, "clang");
+}
+
+static bool IsStdVector(QualType T) {
+  const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
+  if (!TS)
+    return false;
+
+  TemplateName TM = TS->getTemplateName();
+  TemplateDecl *TD = TM.getAsTemplateDecl();
+
+  if (!TD || !InNamespace(TD, "std"))
+    return false;
+
+  return TD->getName() == "vector";
+}
+
+static bool IsSmallVector(QualType T) {
+  const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
+  if (!TS)
+    return false;
+
+  TemplateName TM = TS->getTemplateName();
+  TemplateDecl *TD = TM.getAsTemplateDecl();
+
+  if (!TD || !InNamespace(TD, "llvm"))
+    return false;
+
+  return TD->getName() == "SmallVector";
+}
+
+//===----------------------------------------------------------------------===//
+// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
+// lifetime is shorter than the StringRef's.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
+  BugReporter &BR;
+public:
+  StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
+  void VisitChildren(Stmt *S) {
+    for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
+      I != E; ++I)
+      if (Stmt *child = *I)
+        Visit(child);
+  }
+  void VisitStmt(Stmt *S) { VisitChildren(S); }
+  void VisitDeclStmt(DeclStmt *DS);
+private:
+  void VisitVarDecl(VarDecl *VD);
+};
+} // end anonymous namespace
+
+static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
+  StringRefCheckerVisitor walker(BR);
+  walker.Visit(D->getBody());
+}
+
+void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
+  VisitChildren(S);
+
+  for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
+    if (VarDecl *VD = dyn_cast<VarDecl>(*I))
+      VisitVarDecl(VD);
+}
+
+void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
+  Expr *Init = VD->getInit();
+  if (!Init)
+    return;
+
+  // Pattern match for:
+  // llvm::StringRef x = call() (where call returns std::string)
+  if (!IsLLVMStringRef(VD->getType()))
+    return;
+  ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init);
+  if (!Ex1)
+    return;
+  CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
+  if (!Ex2 || Ex2->getNumArgs() != 1)
+    return;
+  ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
+  if (!Ex3)
+    return;
+  CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
+  if (!Ex4 || Ex4->getNumArgs() != 1)
+    return;
+  ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
+  if (!Ex5)
+    return;
+  CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
+  if (!Ex6 || !IsStdString(Ex6->getType()))
+    return;
+
+  // Okay, badness!  Report an error.
+  const char *desc = "StringRef should not be bound to temporary "
+                     "std::string that it outlives";
+
+  BR.EmitBasicReport(desc, "LLVM Conventions", desc,
+                     VD->getLocStart(), Init->getSourceRange());
+}
+
+//===----------------------------------------------------------------------===//
+// CHECK: Clang AST nodes should not have fields that can allocate
+//   memory.
+//===----------------------------------------------------------------------===//
+
+static bool AllocatesMemory(QualType T) {
+  return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
+}
+
+// This type checking could be sped up via dynamic programming.
+static bool IsPartOfAST(const CXXRecordDecl *R) {
+  if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R))
+    return true;
+
+  for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
+                                                E = R->bases_end(); I!=E; ++I) {
+    CXXBaseSpecifier BS = *I;
+    QualType T = BS.getType();
+    if (const RecordType *baseT = T->getAs<RecordType>()) {
+      CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
+      if (IsPartOfAST(baseD))
+        return true;
+    }
+  }
+
+  return false;
+}
+
+namespace {
+class ASTFieldVisitor {
+  llvm::SmallVector<FieldDecl*, 10> FieldChain;
+  CXXRecordDecl *Root;
+  BugReporter &BR;
+public:
+  ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
+    : Root(root), BR(br) {}
+
+  void Visit(FieldDecl *D);
+  void ReportError(QualType T);
+};
+} // end anonymous namespace
+
+static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
+  if (!IsPartOfAST(R))
+    return;
+
+  for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
+       I != E; ++I) {
+    ASTFieldVisitor walker(R, BR);
+    walker.Visit(*I);
+  }
+}
+
+void ASTFieldVisitor::Visit(FieldDecl *D) {
+  FieldChain.push_back(D);
+
+  QualType T = D->getType();
+
+  if (AllocatesMemory(T))
+    ReportError(T);
+
+  if (const RecordType *RT = T->getAs<RecordType>()) {
+    const RecordDecl *RD = RT->getDecl()->getDefinition();
+    for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+         I != E; ++I)
+      Visit(*I);
+  }
+
+  FieldChain.pop_back();
+}
+
+void ASTFieldVisitor::ReportError(QualType T) {
+  llvm::SmallString<1024> buf;
+  llvm::raw_svector_ostream os(buf);
+
+  os << "AST class '" << Root->getName() << "' has a field '"
+     << FieldChain.front()->getName() << "' that allocates heap memory";
+  if (FieldChain.size() > 1) {
+    os << " via the following chain: ";
+    bool isFirst = true;
+    for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
+         E=FieldChain.end(); I!=E; ++I) {
+      if (!isFirst)
+        os << '.';
+      else
+        isFirst = false;
+      os << (*I)->getName();
+    }
+  }
+  os << " (type " << FieldChain.back()->getType().getAsString() << ")";
+  os.flush();
+
+  // Note that this will fire for every translation unit that uses this
+  // class.  This is suboptimal, but at least scan-build will merge
+  // duplicate HTML reports.  In the future we need a unified way of merging
+  // duplicate reports across translation units.  For C++ classes we cannot
+  // just report warnings when we see an out-of-line method definition for a
+  // class, as that heuristic doesn't always work (the complete definition of
+  // the class may be in the header file, for example).
+  BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
+                     os.str(), FieldChain.front()->getLocStart());
+}
+
+//===----------------------------------------------------------------------===//
+// Entry point for all checks.
+//===----------------------------------------------------------------------===//
+
+static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
+  for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
+       I!=E ; ++I) {
+
+    Decl *D = *I;
+
+    if (D->hasBody())
+      CheckStringRefAssignedTemporary(D, BR);
+
+    if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
+      if (R->isDefinition())
+        CheckASTMemory(R, BR);
+
+    if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
+      ScanCodeDecls(DC_child, BR);
+  }
+}
+
+void ento::CheckLLVMConventions(TranslationUnitDecl &TU,
+                                 BugReporter &BR) {
+  ScanCodeDecls(&TU, BR);
+}
+
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp
new file mode 100644 (file)
index 0000000..44887fa
--- /dev/null
@@ -0,0 +1,142 @@
+// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines MacOSXAPIChecker, which is an assortment of checks on calls
+// to various, widely used Mac OS X functions.
+//
+// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
+// to here, using the new Checker interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
+  enum SubChecks {
+    DispatchOnce = 0,
+    DispatchOnceF,
+    NumChecks
+  };
+
+  BugType *BTypes[NumChecks];
+
+public:
+  MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
+  static void *getTag() { static unsigned tag = 0; return &tag; }
+
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} //end anonymous namespace
+
+void ento::RegisterMacOSXAPIChecker(ExprEngine &Eng) {
+  if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+    Eng.registerCheck(new MacOSXAPIChecker());
+}
+
+//===----------------------------------------------------------------------===//
+// dispatch_once and dispatch_once_f
+//===----------------------------------------------------------------------===//
+
+static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
+                              BugType *&BT, const IdentifierInfo *FI) {
+
+  if (!BT) {
+    llvm::SmallString<128> S;
+    llvm::raw_svector_ostream os(S);
+    os << "Improper use of '" << FI->getName() << '\'';
+    BT = new BugType(os.str(), "Mac OS X API");
+  }
+
+  if (CE->getNumArgs() < 1)
+    return;
+
+  // Check if the first argument is stack allocated.  If so, issue a warning
+  // because that's likely to be bad news.
+  const GRState *state = C.getState();
+  const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+    return;
+
+  ExplodedNode *N = C.generateSink(state);
+  if (!N)
+    return;
+
+  llvm::SmallString<256> S;
+  llvm::raw_svector_ostream os(S);
+  os << "Call to '" << FI->getName() << "' uses";
+  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+    os << " the local variable '" << VR->getDecl()->getName() << '\'';
+  else
+    os << " stack allocated memory";
+  os << " for the predicate value.  Using such transient memory for "
+        "the predicate is potentially dangerous.";
+  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+    os << "  Perhaps you intended to declare the variable as 'static'?";
+
+  EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+  report->addRange(CE->getArg(0)->getSourceRange());
+  C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
+// Central dispatch function.
+//===----------------------------------------------------------------------===//
+
+typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
+                           const IdentifierInfo *FI);
+namespace {
+  class SubCheck {
+    SubChecker SC;
+    BugType **BT;
+  public:
+    SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
+    SubCheck() : SC(NULL), BT(NULL) {}
+
+    void run(CheckerContext &C, const CallExpr *CE,
+             const IdentifierInfo *FI) const {
+      if (SC)
+        SC(C, CE, *BT, FI);
+    }
+  };
+} // end anonymous namespace
+
+void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+  // FIXME: Mostly copy and paste from UnixAPIChecker.  Should refactor.
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const FunctionTextRegion *Fn =
+    dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+
+  if (!Fn)
+    return;
+
+  const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+  if (!FI)
+    return;
+
+  const SubCheck &SC =
+    llvm::StringSwitch<SubCheck>(FI->getName())
+      .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
+      .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
+                                        BTypes[DispatchOnceF]))
+      .Default(SubCheck());
+
+  SC.run(C, CE, FI);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/Makefile b/lib/StaticAnalyzer/EntoSA/Checkers/Makefile
new file mode 100644 (file)
index 0000000..d4de35c
--- /dev/null
@@ -0,0 +1,17 @@
+##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
+# 
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 
+##===----------------------------------------------------------------------===##
+#
+# This implements analyses built on top of source-level CFGs. 
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangStaticAnalyzerCheckers
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp
new file mode 100644 (file)
index 0000000..42243cb
--- /dev/null
@@ -0,0 +1,733 @@
+//=== MallocChecker.cpp - A malloc/free checker -------------------*- 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 malloc/free checker, which checks for potential memory
+// leaks, double free, and use-after-free problems.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineExperimentalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableMap.h"
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class RefState {
+  enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped,
+              Relinquished } K;
+  const Stmt *S;
+
+public:
+  RefState(Kind k, const Stmt *s) : K(k), S(s) {}
+
+  bool isAllocated() const { return K == AllocateUnchecked; }
+  //bool isFailed() const { return K == AllocateFailed; }
+  bool isReleased() const { return K == Released; }
+  //bool isEscaped() const { return K == Escaped; }
+  //bool isRelinquished() const { return K == Relinquished; }
+
+  bool operator==(const RefState &X) const {
+    return K == X.K && S == X.S;
+  }
+
+  static RefState getAllocateUnchecked(const Stmt *s) { 
+    return RefState(AllocateUnchecked, s); 
+  }
+  static RefState getAllocateFailed() {
+    return RefState(AllocateFailed, 0);
+  }
+  static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
+  static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
+  static RefState getRelinquished(const Stmt *s) {
+    return RefState(Relinquished, s);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(K);
+    ID.AddPointer(S);
+  }
+};
+
+class RegionState {};
+
+class MallocChecker : public CheckerVisitor<MallocChecker> {
+  BuiltinBug *BT_DoubleFree;
+  BuiltinBug *BT_Leak;
+  BuiltinBug *BT_UseFree;
+  BuiltinBug *BT_UseRelinquished;
+  BuiltinBug *BT_BadFree;
+  IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
+
+public:
+  MallocChecker() 
+    : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0),
+      BT_BadFree(0),
+      II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
+  static void *getTag();
+  bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+  void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
+  void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
+  void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+  const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption,
+                            bool *respondsToCallback);
+  void visitLocation(CheckerContext &C, const Stmt *S, SVal l);
+  virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
+                            SVal location, SVal val);
+
+private:
+  void MallocMem(CheckerContext &C, const CallExpr *CE);
+  void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
+                            const OwnershipAttr* Att);
+  const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+                              const Expr *SizeEx, SVal Init,
+                              const GRState *state) {
+    return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
+  }
+  const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
+                              SVal SizeEx, SVal Init,
+                              const GRState *state);
+
+  void FreeMem(CheckerContext &C, const CallExpr *CE);
+  void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
+                   const OwnershipAttr* Att);
+  const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
+                            const GRState *state, unsigned Num, bool Hold);
+
+  void ReallocMem(CheckerContext &C, const CallExpr *CE);
+  void CallocMem(CheckerContext &C, const CallExpr *CE);
+  
+  bool SummarizeValue(llvm::raw_ostream& os, SVal V);
+  bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
+  void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range);
+};
+} // end anonymous namespace
+
+typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
+
+namespace clang {
+namespace ento {
+  template <>
+  struct GRStateTrait<RegionState> 
+    : public GRStatePartialTrait<RegionStateTy> {
+    static void *GDMIndex() { return MallocChecker::getTag(); }
+  };
+}
+}
+
+void ento::RegisterMallocChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new MallocChecker());
+}
+
+void *MallocChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+bool MallocChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+
+  const FunctionDecl *FD = L.getAsFunctionDecl();
+  if (!FD)
+    return false;
+
+  ASTContext &Ctx = C.getASTContext();
+  if (!II_malloc)
+    II_malloc = &Ctx.Idents.get("malloc");
+  if (!II_free)
+    II_free = &Ctx.Idents.get("free");
+  if (!II_realloc)
+    II_realloc = &Ctx.Idents.get("realloc");
+  if (!II_calloc)
+    II_calloc = &Ctx.Idents.get("calloc");
+
+  if (FD->getIdentifier() == II_malloc) {
+    MallocMem(C, CE);
+    return true;
+  }
+
+  if (FD->getIdentifier() == II_free) {
+    FreeMem(C, CE);
+    return true;
+  }
+
+  if (FD->getIdentifier() == II_realloc) {
+    ReallocMem(C, CE);
+    return true;
+  }
+
+  if (FD->getIdentifier() == II_calloc) {
+    CallocMem(C, CE);
+    return true;
+  }
+
+  // Check all the attributes, if there are any.
+  // There can be multiple of these attributes.
+  bool rv = false;
+  if (FD->hasAttrs()) {
+    for (specific_attr_iterator<OwnershipAttr>
+                  i = FD->specific_attr_begin<OwnershipAttr>(),
+                  e = FD->specific_attr_end<OwnershipAttr>();
+         i != e; ++i) {
+      switch ((*i)->getOwnKind()) {
+      case OwnershipAttr::Returns: {
+        MallocMemReturnsAttr(C, CE, *i);
+        rv = true;
+        break;
+      }
+      case OwnershipAttr::Takes:
+      case OwnershipAttr::Holds: {
+        FreeMemAttr(C, CE, *i);
+        rv = true;
+        break;
+      }
+      default:
+        break;
+      }
+    }
+  }
+  return rv;
+}
+
+void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(),
+                                      C.getState());
+  C.addTransition(state);
+}
+
+void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
+                                         const OwnershipAttr* Att) {
+  if (Att->getModule() != "malloc")
+    return;
+
+  OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
+  if (I != E) {
+    const GRState *state =
+        MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
+    C.addTransition(state);
+    return;
+  }
+  const GRState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(),
+                                        C.getState());
+  C.addTransition(state);
+}
+
+const GRState *MallocChecker::MallocMemAux(CheckerContext &C,  
+                                           const CallExpr *CE,
+                                           SVal Size, SVal Init,
+                                           const GRState *state) {
+  unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+
+  // Set the return value.
+  SVal retVal = svalBuilder.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
+  state = state->BindExpr(CE, retVal);
+
+  // Fill the region with the initialization value.
+  state = state->bindDefault(retVal, Init);
+
+  // Set the region's extent equal to the Size parameter.
+  const SymbolicRegion *R = cast<SymbolicRegion>(retVal.getAsRegion());
+  DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
+  DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
+  DefinedOrUnknownSVal extentMatchesSize =
+    svalBuilder.evalEQ(state, Extent, DefinedSize);
+
+  state = state->assume(extentMatchesSize, true);
+  assert(state);
+  
+  SymbolRef Sym = retVal.getAsLocSymbol();
+  assert(Sym);
+
+  // Set the symbol's state to Allocated.
+  return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
+}
+
+void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
+
+  if (state)
+    C.addTransition(state);
+}
+
+void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
+                                const OwnershipAttr* Att) {
+  if (Att->getModule() != "malloc")
+    return;
+
+  for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
+       I != E; ++I) {
+    const GRState *state = FreeMemAux(C, CE, C.getState(), *I,
+                                      Att->getOwnKind() == OwnershipAttr::Holds);
+    if (state)
+      C.addTransition(state);
+  }
+}
+
+const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
+                                         const GRState *state, unsigned Num,
+                                         bool Hold) {
+  const Expr *ArgExpr = CE->getArg(Num);
+  SVal ArgVal = state->getSVal(ArgExpr);
+
+  DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
+
+  // Check for null dereferences.
+  if (!isa<Loc>(location))
+    return state;
+
+  // FIXME: Technically using 'Assume' here can result in a path
+  //  bifurcation.  In such cases we need to return two states, not just one.
+  const GRState *notNullState, *nullState;
+  llvm::tie(notNullState, nullState) = state->assume(location);
+
+  // The explicit NULL case, no operation is performed.
+  if (nullState && !notNullState)
+    return nullState;
+
+  assert(notNullState);
+
+  // Unknown values could easily be okay
+  // Undefined values are handled elsewhere
+  if (ArgVal.isUnknownOrUndef())
+    return notNullState;
+
+  const MemRegion *R = ArgVal.getAsRegion();
+  
+  // Nonlocs can't be freed, of course.
+  // Non-region locations (labels and fixed addresses) also shouldn't be freed.
+  if (!R) {
+    ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+    return NULL;
+  }
+  
+  R = R->StripCasts();
+  
+  // Blocks might show up as heap data, but should not be free()d
+  if (isa<BlockDataRegion>(R)) {
+    ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+    return NULL;
+  }
+  
+  const MemSpaceRegion *MS = R->getMemorySpace();
+  
+  // Parameters, locals, statics, and globals shouldn't be freed.
+  if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
+    // FIXME: at the time this code was written, malloc() regions were
+    // represented by conjured symbols, which are all in UnknownSpaceRegion.
+    // This means that there isn't actually anything from HeapSpaceRegion
+    // that should be freed, even though we allow it here.
+    // Of course, free() can work on memory allocated outside the current
+    // function, so UnknownSpaceRegion is always a possibility.
+    // False negatives are better than false positives.
+    
+    ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+    return NULL;
+  }
+  
+  const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+  // Various cases could lead to non-symbol values here.
+  // For now, ignore them.
+  if (!SR)
+    return notNullState;
+
+  SymbolRef Sym = SR->getSymbol();
+  const RefState *RS = state->get<RegionState>(Sym);
+
+  // If the symbol has not been tracked, return. This is possible when free() is
+  // called on a pointer that does not get its pointee directly from malloc(). 
+  // Full support of this requires inter-procedural analysis.
+  if (!RS)
+    return notNullState;
+
+  // Check double free.
+  if (RS->isReleased()) {
+    if (ExplodedNode *N = C.generateSink()) {
+      if (!BT_DoubleFree)
+        BT_DoubleFree
+          = new BuiltinBug("Double free",
+                         "Try to free a memory block that has been released");
+      // FIXME: should find where it's freed last time.
+      BugReport *R = new BugReport(*BT_DoubleFree, 
+                                   BT_DoubleFree->getDescription(), N);
+      C.EmitReport(R);
+    }
+    return NULL;
+  }
+
+  // Normal free.
+  if (Hold)
+    return notNullState->set<RegionState>(Sym, RefState::getRelinquished(CE));
+  return notNullState->set<RegionState>(Sym, RefState::getReleased(CE));
+}
+
+bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) {
+  if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V))
+    os << "an integer (" << IntVal->getValue() << ")";
+  else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V))
+    os << "a constant address (" << ConstAddr->getValue() << ")";
+  else if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&V))
+    os << "the address of the label '"
+       << Label->getLabel()->getID()->getName()
+       << "'";
+  else
+    return false;
+  
+  return true;
+}
+
+bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os,
+                                    const MemRegion *MR) {
+  switch (MR->getKind()) {
+  case MemRegion::FunctionTextRegionKind: {
+    const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+    if (FD)
+      os << "the address of the function '" << FD << "'";
+    else
+      os << "the address of a function";
+    return true;
+  }
+  case MemRegion::BlockTextRegionKind:
+    os << "block text";
+    return true;
+  case MemRegion::BlockDataRegionKind:
+    // FIXME: where the block came from?
+    os << "a block";
+    return true;
+  default: {
+    const MemSpaceRegion *MS = MR->getMemorySpace();
+    
+    switch (MS->getKind()) {
+    case MemRegion::StackLocalsSpaceRegionKind: {
+      const VarRegion *VR = dyn_cast<VarRegion>(MR);
+      const VarDecl *VD;
+      if (VR)
+        VD = VR->getDecl();
+      else
+        VD = NULL;
+      
+      if (VD)
+        os << "the address of the local variable '" << VD->getName() << "'";
+      else
+        os << "the address of a local stack variable";
+      return true;
+    }
+    case MemRegion::StackArgumentsSpaceRegionKind: {
+      const VarRegion *VR = dyn_cast<VarRegion>(MR);
+      const VarDecl *VD;
+      if (VR)
+        VD = VR->getDecl();
+      else
+        VD = NULL;
+      
+      if (VD)
+        os << "the address of the parameter '" << VD->getName() << "'";
+      else
+        os << "the address of a parameter";
+      return true;
+    }
+    case MemRegion::NonStaticGlobalSpaceRegionKind:
+    case MemRegion::StaticGlobalSpaceRegionKind: {
+      const VarRegion *VR = dyn_cast<VarRegion>(MR);
+      const VarDecl *VD;
+      if (VR)
+        VD = VR->getDecl();
+      else
+        VD = NULL;
+      
+      if (VD) {
+        if (VD->isStaticLocal())
+          os << "the address of the static variable '" << VD->getName() << "'";
+        else
+          os << "the address of the global variable '" << VD->getName() << "'";
+      } else
+        os << "the address of a global variable";
+      return true;
+    }
+    default:
+      return false;
+    }
+  }
+  }
+}
+
+void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
+                                  SourceRange range) {
+  if (ExplodedNode *N = C.generateSink()) {
+    if (!BT_BadFree)
+      BT_BadFree = new BuiltinBug("Bad free");
+    
+    llvm::SmallString<100> buf;
+    llvm::raw_svector_ostream os(buf);
+    
+    const MemRegion *MR = ArgVal.getAsRegion();
+    if (MR) {
+      while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR))
+        MR = ER->getSuperRegion();
+      
+      // Special case for alloca()
+      if (isa<AllocaRegion>(MR))
+        os << "Argument to free() was allocated by alloca(), not malloc()";
+      else {
+        os << "Argument to free() is ";
+        if (SummarizeRegion(os, MR))
+          os << ", which is not memory allocated by malloc()";
+        else
+          os << "not memory allocated by malloc()";
+      }
+    } else {
+      os << "Argument to free() is ";
+      if (SummarizeValue(os, ArgVal))
+        os << ", which is not memory allocated by malloc()";
+      else
+        os << "not memory allocated by malloc()";
+    }
+    
+    EnhancedBugReport *R = new EnhancedBugReport(*BT_BadFree, os.str(), N);
+    R->addRange(range);
+    C.EmitReport(R);
+  }
+}
+
+void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *arg0Expr = CE->getArg(0);
+  DefinedOrUnknownSVal arg0Val 
+    = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr));
+
+  SValBuilder &svalBuilder = C.getSValBuilder();
+
+  DefinedOrUnknownSVal PtrEQ =
+    svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
+
+  // If the ptr is NULL, the call is equivalent to malloc(size).
+  if (const GRState *stateEqual = state->assume(PtrEQ, true)) {
+    // Hack: set the NULL symbolic region to released to suppress false warning.
+    // In the future we should add more states for allocated regions, e.g., 
+    // CheckedNull, CheckedNonNull.
+    
+    SymbolRef Sym = arg0Val.getAsLocSymbol();
+    if (Sym)
+      stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
+
+    const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), 
+                                              UndefinedVal(), stateEqual);
+    C.addTransition(stateMalloc);
+  }
+
+  if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) {
+    const Expr *Arg1 = CE->getArg(1);
+    DefinedOrUnknownSVal Arg1Val = 
+      cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
+    DefinedOrUnknownSVal SizeZero =
+      svalBuilder.evalEQ(stateNotEqual, Arg1Val,
+                         svalBuilder.makeIntValWithPtrWidth(0, false));
+
+    if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
+      if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false))
+        C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
+
+    if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
+      if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
+                                                0, false)) {
+        // FIXME: We should copy the content of the original buffer.
+        const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), 
+                                                   UnknownVal(), stateFree);
+        C.addTransition(stateRealloc);
+      }
+  }
+}
+
+void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+
+  SVal count = state->getSVal(CE->getArg(0));
+  SVal elementSize = state->getSVal(CE->getArg(1));
+  SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
+                                        svalBuilder.getContext().getSizeType());  
+  SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
+
+  C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
+}
+
+void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
+{
+  if (!SymReaper.hasDeadSymbols())
+    return;
+
+  const GRState *state = C.getState();
+  RegionStateTy RS = state->get<RegionState>();
+  RegionStateTy::Factory &F = state->get_context<RegionState>();
+
+  for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+    if (SymReaper.isDead(I->first)) {
+      if (I->second.isAllocated()) {
+        if (ExplodedNode *N = C.generateNode()) {
+          if (!BT_Leak)
+            BT_Leak = new BuiltinBug("Memory leak",
+                     "Allocated memory never released. Potential memory leak.");
+          // FIXME: where it is allocated.
+          BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+          C.EmitReport(R);
+        }
+      }
+
+      // Remove the dead symbol from the map.
+      RS = F.remove(RS, I->first);
+    }
+  }
+  C.generateNode(state->set<RegionState>(RS));
+}
+
+void MallocChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
+                                ExprEngine &Eng) {
+  SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
+  const GRState *state = B.getState();
+  RegionStateTy M = state->get<RegionState>();
+
+  for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+    RefState RS = I->second;
+    if (RS.isAllocated()) {
+      ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+      if (N) {
+        if (!BT_Leak)
+          BT_Leak = new BuiltinBug("Memory leak",
+                     "Allocated memory never released. Potential memory leak.");
+        BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+        Eng.getBugReporter().EmitReport(R);
+      }
+    }
+  }
+}
+
+void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+  const Expr *retExpr = S->getRetValue();
+  if (!retExpr)
+    return;
+
+  const GRState *state = C.getState();
+
+  SymbolRef Sym = state->getSVal(retExpr).getAsSymbol();
+  if (!Sym)
+    return;
+
+  const RefState *RS = state->get<RegionState>(Sym);
+  if (!RS)
+    return;
+
+  // FIXME: check other cases.
+  if (RS->isAllocated())
+    state = state->set<RegionState>(Sym, RefState::getEscaped(S));
+
+  C.addTransition(state);
+}
+
+const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, 
+                                         bool Assumption,
+                                         bool * /* respondsToCallback */) {
+  // If a symblic region is assumed to NULL, set its state to AllocateFailed.
+  // FIXME: should also check symbols assumed to non-null.
+
+  RegionStateTy RS = state->get<RegionState>();
+
+  for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+    if (state->getSymVal(I.getKey()))
+      state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
+  }
+
+  return state;
+}
+
+// Check if the location is a freed symbolic region.
+void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l) {
+  SymbolRef Sym = l.getLocSymbolInBase();
+  if (Sym) {
+    const RefState *RS = C.getState()->get<RegionState>(Sym);
+    if (RS && RS->isReleased()) {
+      if (ExplodedNode *N = C.generateNode()) {
+        if (!BT_UseFree)
+          BT_UseFree = new BuiltinBug("Use dynamically allocated memory after"
+                                      " it is freed.");
+
+        BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
+                                     N);
+        C.EmitReport(R);
+      }
+    }
+  }
+}
+
+void MallocChecker::PreVisitBind(CheckerContext &C,
+                                 const Stmt *StoreE,
+                                 SVal location,
+                                 SVal val) {
+  // The PreVisitBind implements the same algorithm as already used by the 
+  // Objective C ownership checker: if the pointer escaped from this scope by 
+  // assignment, let it go.  However, assigning to fields of a stack-storage 
+  // structure does not transfer ownership.
+
+  const GRState *state = C.getState();
+  DefinedOrUnknownSVal l = cast<DefinedOrUnknownSVal>(location);
+
+  // Check for null dereferences.
+  if (!isa<Loc>(l))
+    return;
+
+  // Before checking if the state is null, check if 'val' has a RefState.
+  // Only then should we check for null and bifurcate the state.
+  SymbolRef Sym = val.getLocSymbolInBase();
+  if (Sym) {
+    if (const RefState *RS = state->get<RegionState>(Sym)) {
+      // If ptr is NULL, no operation is performed.
+      const GRState *notNullState, *nullState;
+      llvm::tie(notNullState, nullState) = state->assume(l);
+
+      // Generate a transition for 'nullState' to record the assumption
+      // that the state was null.
+      if (nullState)
+        C.addTransition(nullState);
+
+      if (!notNullState)
+        return;
+
+      if (RS->isAllocated()) {
+        // Something we presently own is being assigned somewhere.
+        const MemRegion *AR = location.getAsRegion();
+        if (!AR)
+          return;
+        AR = AR->StripCasts()->getBaseRegion();
+        do {
+          // If it is on the stack, we still own it.
+          if (AR->hasStackNonParametersStorage())
+            break;
+
+          // If the state can't represent this binding, we still own it.
+          if (notNullState == (notNullState->bindLoc(cast<Loc>(location),
+                                                     UnknownVal())))
+            break;
+
+          // We no longer own this pointer.
+          notNullState =
+            notNullState->set<RegionState>(Sym,
+                                           RefState::getRelinquished(StoreE));
+        }
+        while (false);
+      }
+      C.addTransition(notNullState);
+    }
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp
new file mode 100644 (file)
index 0000000..6ef242b
--- /dev/null
@@ -0,0 +1,87 @@
+//=- NSAutoreleasePoolChecker.cpp --------------------------------*- 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 a NSAutoreleasePoolChecker, a small checker that warns
+//  about subpar uses of NSAutoreleasePool.  Note that while the check itself
+//  (in it's current form) could be written as a flow-insensitive check, in
+//  can be potentially enhanced in the future with flow-sensitive information.
+//  It is also a good example of the CheckerVisitor interface. 
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "BasicObjCFoundationChecks.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Decl.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class NSAutoreleasePoolChecker
+  : public CheckerVisitor<NSAutoreleasePoolChecker> {
+      
+  Selector releaseS;
+
+public:
+    NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
+    
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+
+  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);    
+};
+
+} // end anonymous namespace
+
+
+void ento::RegisterNSAutoreleasePoolChecks(ExprEngine &Eng) {
+  ASTContext &Ctx = Eng.getContext();
+  if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {    
+    Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
+                                                                      Ctx)));
+  }
+}
+
+void
+NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+                                                  const ObjCMessageExpr *ME) {
+  
+  const Expr *receiver = ME->getInstanceReceiver();
+  if (!receiver)
+    return;
+  
+  // FIXME: Enhance with value-tracking information instead of consulting
+  // the type of the expression.
+  const ObjCObjectPointerType* PT =
+    receiver->getType()->getAs<ObjCObjectPointerType>();
+  
+  if (!PT)
+    return;  
+  const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
+  if (!OD)
+    return;  
+  if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
+    return;
+  
+  // Sending 'release' message?
+  if (ME->getSelector() != releaseS)
+    return;
+                     
+  SourceRange R = ME->getSourceRange();
+
+  C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
+    "API Upgrade (Apple)",
+    "Use -drain instead of -release when using NSAutoreleasePool "
+    "and garbage collection", ME->getLocStart(), &R, 1);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp
new file mode 100644 (file)
index 0000000..54e6118
--- /dev/null
@@ -0,0 +1,238 @@
+//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- 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 a CheckNSError, a flow-insenstive check
+//  that determines if an Objective-C class interface correctly returns
+//  a non-void return type.
+//
+//  File under feature request PR 2600.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
+#include "BasicObjCFoundationChecks.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class NSErrorChecker : public BugType {
+  const Decl &CodeDecl;
+  const bool isNSErrorWarning;
+  IdentifierInfo * const II;
+  ExprEngine &Eng;
+
+  void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy,
+                      llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
+
+  void CheckSignature(const FunctionDecl& MD, QualType& ResultTy,
+                      llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
+
+  bool CheckNSErrorArgument(QualType ArgTy);
+  bool CheckCFErrorArgument(QualType ArgTy);
+
+  void CheckParamDeref(const VarDecl *V, const LocationContext *LC,
+                       const GRState *state, BugReporter& BR);
+
+  void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl);
+
+public:
+  NSErrorChecker(const Decl &D, bool isNSError, ExprEngine& eng)
+    : BugType(isNSError ? "NSError** null dereference"
+                        : "CFErrorRef* null dereference",
+              "Coding conventions (Apple)"),
+    CodeDecl(D),
+    isNSErrorWarning(isNSError),
+    II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")),
+    Eng(eng) {}
+
+  void FlushReports(BugReporter& BR);
+};
+
+} // end anonymous namespace
+
+void ento::RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng,
+                                  const Decl &D) {
+  BR.Register(new NSErrorChecker(D, true, Eng));
+  BR.Register(new NSErrorChecker(D, false, Eng));
+}
+
+void NSErrorChecker::FlushReports(BugReporter& BR) {
+  // Get the analysis engine and the exploded analysis graph.
+  ExplodedGraph& G = Eng.getGraph();
+
+  // Get the ASTContext, which is useful for querying type information.
+  ASTContext &Ctx = BR.getContext();
+
+  QualType ResultTy;
+  llvm::SmallVector<VarDecl*, 5> ErrorParams;
+
+  if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl))
+    CheckSignature(*MD, ResultTy, ErrorParams);
+  else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl))
+    CheckSignature(*FD, ResultTy, ErrorParams);
+  else
+    return;
+
+  if (ErrorParams.empty())
+    return;
+
+  if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl);
+
+  for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end();
+       RI!=RE; ++RI) {
+    // Scan the parameters for an implicit null dereference.
+    for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(),
+          E=ErrorParams.end(); I!=E; ++I)
+        CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR);
+  }
+}
+
+void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
+  std::string sbuf;
+  llvm::raw_string_ostream os(sbuf);
+
+  if (isa<ObjCMethodDecl>(CodeDecl))
+    os << "Method";
+  else
+    os << "Function";
+
+  os << " accepting ";
+  os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*");
+  os << " should have a non-void return value to indicate whether or not an "
+        "error occurred";
+
+  BR.EmitBasicReport(isNSErrorWarning
+                     ? "Bad return type when passing NSError**"
+                     : "Bad return type when passing CFError*",
+                     getCategory(), os.str(),
+                     CodeDecl.getLocation());
+}
+
+void
+NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
+                             llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
+
+  ResultTy = M.getResultType();
+
+  for (ObjCMethodDecl::param_iterator I=M.param_begin(),
+       E=M.param_end(); I!=E; ++I)  {
+
+    QualType T = (*I)->getType();
+
+    if (isNSErrorWarning) {
+      if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
+    }
+    else if (CheckCFErrorArgument(T))
+      ErrorParams.push_back(*I);
+  }
+}
+
+void
+NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy,
+                             llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
+
+  ResultTy = F.getResultType();
+
+  for (FunctionDecl::param_const_iterator I = F.param_begin(),
+                                          E = F.param_end(); I != E; ++I)  {
+
+    QualType T = (*I)->getType();
+
+    if (isNSErrorWarning) {
+      if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
+    }
+    else if (CheckCFErrorArgument(T))
+      ErrorParams.push_back(*I);
+  }
+}
+
+
+bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) {
+
+  const PointerType* PPT = ArgTy->getAs<PointerType>();
+  if (!PPT)
+    return false;
+
+  const ObjCObjectPointerType* PT =
+    PPT->getPointeeType()->getAs<ObjCObjectPointerType>();
+
+  if (!PT)
+    return false;
+
+  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
+
+  // FIXME: Can ID ever be NULL?
+  if (ID)
+    return II == ID->getIdentifier();
+
+  return false;
+}
+
+bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) {
+
+  const PointerType* PPT = ArgTy->getAs<PointerType>();
+  if (!PPT) return false;
+
+  const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>();
+  if (!TT) return false;
+
+  return TT->getDecl()->getIdentifier() == II;
+}
+
+void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
+                                   const LocationContext *LC,
+                                   const GRState *rootState,
+                                   BugReporter& BR) {
+
+  SVal ParamL = rootState->getLValue(Param, LC);
+  const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>();
+  assert (ParamR && "Parameters always have VarRegions.");
+  SVal ParamSVal = rootState->getSVal(ParamR);
+
+  // FIXME: For now assume that ParamSVal is symbolic.  We need to generalize
+  // this later.
+  SymbolRef ParamSym = ParamSVal.getAsLocSymbol();
+  if (!ParamSym)
+    return;
+
+  // Iterate over the implicit-null dereferences.
+  ExplodedNode *const* I,  *const* E;
+  llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
+  for ( ; I != E; ++I) {
+    const GRState *state = (*I)->getState();
+    SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
+    if (location.getAsSymbol() != ParamSym)
+      continue;
+
+    // Emit an error.
+    std::string sbuf;
+    llvm::raw_string_ostream os(sbuf);
+      os << "Potential null dereference.  According to coding standards ";
+
+    if (isNSErrorWarning)
+      os << "in 'Creating and Returning NSError Objects' the parameter '";
+    else
+      os << "documented in CoreFoundation/CFError.h the parameter '";
+
+    os << Param << "' may be null.";
+
+    BugReport *report = new BugReport(*this, os.str(), *I);
+    // FIXME: Notable symbols are now part of the report.  We should
+    //  add support for notable symbols in BugReport.
+    //    BR.addNotableSymbol(SV->getSymbol());
+    BR.EmitReport(report);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp
new file mode 100644 (file)
index 0000000..8cdc04f
--- /dev/null
@@ -0,0 +1,80 @@
+//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NoReturnFunctionChecker, which evaluates functions that do not
+// return to the caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> {
+public:
+  static void *getTag() { static int tag = 0; return &tag; }
+  void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void ento::RegisterNoReturnFunctionChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new NoReturnFunctionChecker());
+}
+
+void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C,
+                                                const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+
+  bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
+
+  if (!BuildSinks) {
+    SVal L = state->getSVal(Callee);
+    const FunctionDecl *FD = L.getAsFunctionDecl();
+    if (!FD)
+      return;
+
+    if (FD->getAttr<AnalyzerNoReturnAttr>())
+      BuildSinks = true;
+    else if (const IdentifierInfo *II = FD->getIdentifier()) {
+      // HACK: Some functions are not marked noreturn, and don't return.
+      //  Here are a few hardwired ones.  If this takes too long, we can
+      //  potentially cache these results.
+      BuildSinks
+        = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
+            .Case("exit", true)
+            .Case("panic", true)
+            .Case("error", true)
+            .Case("Assert", true)
+            // FIXME: This is just a wrapper around throwing an exception.
+            //  Eventually inter-procedural analysis should handle this easily.
+            .Case("ziperr", true)
+            .Case("assfail", true)
+            .Case("db_error", true)
+            .Case("__assert", true)
+            .Case("__assert_rtn", true)
+            .Case("__assert_fail", true)
+            .Case("dtrace_assfail", true)
+            .Case("yy_fatal_error", true)
+            .Case("_XCAssertionFailureHandler", true)
+            .Case("_DTAssertionFailureHandler", true)
+            .Case("_TSAssertionFailureHandler", true)
+            .Default(false);
+    }
+  }
+
+  if (BuildSinks)
+    C.generateSink(CE);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp
new file mode 100644 (file)
index 0000000..9931734
--- /dev/null
@@ -0,0 +1,203 @@
+//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker evaluates OSAtomic functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+#include "clang/Basic/Builtins.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class OSAtomicChecker : public Checker {
+public:
+  static void *getTag() { static int tag = 0; return &tag; }
+  virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+
+private:
+  bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
+};
+
+}
+
+void ento::RegisterOSAtomicChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new OSAtomicChecker());
+}
+
+bool OSAtomicChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+
+  const FunctionDecl* FD = L.getAsFunctionDecl();
+  if (!FD)
+    return false;
+
+  const IdentifierInfo *II = FD->getIdentifier();
+  if (!II)
+    return false;
+  
+  llvm::StringRef FName(II->getName());
+
+  // Check for compare and swap.
+  if (FName.startswith("OSAtomicCompareAndSwap") ||
+      FName.startswith("objc_atomicCompareAndSwap"))
+    return evalOSAtomicCompareAndSwap(C, CE);
+
+  // FIXME: Other atomics.
+  return false;
+}
+
+bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, 
+                                                 const CallExpr *CE) {
+  // Not enough arguments to match OSAtomicCompareAndSwap?
+  if (CE->getNumArgs() != 3)
+    return false;
+
+  ASTContext &Ctx = C.getASTContext();
+  const Expr *oldValueExpr = CE->getArg(0);
+  QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
+
+  const Expr *newValueExpr = CE->getArg(1);
+  QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
+
+  // Do the types of 'oldValue' and 'newValue' match?
+  if (oldValueType != newValueType)
+    return false;
+
+  const Expr *theValueExpr = CE->getArg(2);
+  const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
+
+  // theValueType not a pointer?
+  if (!theValueType)
+    return false;
+
+  QualType theValueTypePointee =
+    Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
+
+  // The pointee must match newValueType and oldValueType.
+  if (theValueTypePointee != newValueType)
+    return false;
+
+  static unsigned magic_load = 0;
+  static unsigned magic_store = 0;
+
+  const void *OSAtomicLoadTag = &magic_load;
+  const void *OSAtomicStoreTag = &magic_store;
+
+  // Load 'theValue'.
+  ExprEngine &Engine = C.getEngine();
+  const GRState *state = C.getState();
+  ExplodedNodeSet Tmp;
+  SVal location = state->getSVal(theValueExpr);
+  // Here we should use the value type of the region as the load type, because
+  // we are simulating the semantics of the function, not the semantics of 
+  // passing argument. So the type of theValue expr is not we are loading.
+  // But usually the type of the varregion is not the type we want either,
+  // we still need to do a CastRetrievedVal in store manager. So actually this
+  // LoadTy specifying can be omitted. But we put it here to emphasize the 
+  // semantics.
+  QualType LoadTy;
+  if (const TypedRegion *TR =
+      dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+    LoadTy = TR->getValueType();
+  }
+  Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(), 
+                  state, location, OSAtomicLoadTag, LoadTy);
+
+  if (Tmp.empty()) {
+    // If no nodes were generated, other checkers must generated sinks. But 
+    // since the builder state was restored, we set it manually to prevent 
+    // auto transition.
+    // FIXME: there should be a better approach.
+    C.getNodeBuilder().BuildSinks = true;
+    return true;
+  }
+  for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
+       I != E; ++I) {
+
+    ExplodedNode *N = *I;
+    const GRState *stateLoad = N->getState();
+    SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
+    SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
+
+    // FIXME: Issue an error.
+    if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
+      return false;
+    }
+    
+    DefinedOrUnknownSVal theValueVal =
+      cast<DefinedOrUnknownSVal>(theValueVal_untested);
+    DefinedOrUnknownSVal oldValueVal =
+      cast<DefinedOrUnknownSVal>(oldValueVal_untested);
+
+    SValBuilder &svalBuilder = Engine.getSValBuilder();
+
+    // Perform the comparison.
+    DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
+
+    const GRState *stateEqual = stateLoad->assume(Cmp, true);
+
+    // Were they equal?
+    if (stateEqual) {
+      // Perform the store.
+      ExplodedNodeSet TmpStore;
+      SVal val = stateEqual->getSVal(newValueExpr);
+
+      // Handle implicit value casts.
+      if (const TypedRegion *R =
+          dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
+        val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
+      }
+
+      Engine.evalStore(TmpStore, NULL, theValueExpr, N, 
+                       stateEqual, location, val, OSAtomicStoreTag);
+
+      if (TmpStore.empty()) {
+        // If no nodes were generated, other checkers must generated sinks. But 
+        // since the builder state was restored, we set it manually to prevent 
+        // auto transition.
+        // FIXME: there should be a better approach.
+        C.getNodeBuilder().BuildSinks = true;
+        return true;
+      }
+
+      // Now bind the result of the comparison.
+      for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
+           E2 = TmpStore.end(); I2 != E2; ++I2) {
+        ExplodedNode *predNew = *I2;
+        const GRState *stateNew = predNew->getState();
+        // Check for 'void' return type if we have a bogus function prototype.
+        SVal Res = UnknownVal();
+        QualType T = CE->getType();
+        if (!T->isVoidType())
+          Res = Engine.getSValBuilder().makeTruthVal(true, T);
+        C.generateNode(stateNew->BindExpr(CE, Res), predNew);
+      }
+    }
+
+    // Were they not equal?
+    if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
+      // Check for 'void' return type if we have a bogus function prototype.
+      SVal Res = UnknownVal();
+      QualType T = CE->getType();
+      if (!T->isVoidType())
+        Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
+      C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
+    }
+  }
+
+  return true;
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp
new file mode 100644 (file)
index 0000000..2d94e8c
--- /dev/null
@@ -0,0 +1,95 @@
+//== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- C++ -*--=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines ObjCAtSyncChecker, a builtin check that checks for null pointers
+// used as mutexes for @synchronized.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
+  BuiltinBug *BT_null;
+  BuiltinBug *BT_undef;
+public:
+  ObjCAtSyncChecker() : BT_null(0), BT_undef(0) {}
+  static void *getTag() { static int tag = 0; return &tag; }
+  void PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
+                                      const ObjCAtSynchronizedStmt *S);
+};
+} // end anonymous namespace
+
+void ento::RegisterObjCAtSyncChecker(ExprEngine &Eng) {
+  // @synchronized is an Objective-C 2 feature.
+  if (Eng.getContext().getLangOptions().ObjC2)
+    Eng.registerCheck(new ObjCAtSyncChecker());
+}
+
+void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
+                                         const ObjCAtSynchronizedStmt *S) {
+
+  const Expr *Ex = S->getSynchExpr();
+  const GRState *state = C.getState();
+  SVal V = state->getSVal(Ex);
+
+  // Uninitialized value used for the mutex?
+  if (isa<UndefinedVal>(V)) {
+    if (ExplodedNode *N = C.generateSink()) {
+      if (!BT_undef)
+        BT_undef = new BuiltinBug("Uninitialized value used as mutex "
+                                  "for @synchronized");
+      EnhancedBugReport *report =
+        new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
+      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+      C.EmitReport(report);
+    }
+    return;
+  }
+
+  if (V.isUnknown())
+    return;
+
+  // Check for null mutexes.
+  const GRState *notNullState, *nullState;
+  llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
+
+  if (nullState) {
+    if (!notNullState) {
+      // Generate an error node.  This isn't a sink since
+      // a null mutex just means no synchronization occurs.
+      if (ExplodedNode *N = C.generateNode(nullState)) {
+        if (!BT_null)
+          BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
+                                   "(no synchronization will occur)");
+        EnhancedBugReport *report =
+          new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
+        report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                                  Ex);
+
+        C.EmitReport(report);
+        return;
+      }
+    }
+    // Don't add a transition for 'nullState'.  If the value is
+    // under-constrained to be null or non-null, assume it is non-null
+    // afterwards.
+  }
+
+  if (notNullState)
+    C.addTransition(notNullState);
+}
+
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp
new file mode 100644 (file)
index 0000000..799da33
--- /dev/null
@@ -0,0 +1,164 @@
+//==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- 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 a CheckObjCUnusedIvars, a checker that
+//  analyzes an Objective-C class's interface/implementation to determine if it
+//  has any ivars that are never accessed.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+using namespace ento;
+
+enum IVarState { Unused, Used };
+typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
+
+static void Scan(IvarUsageMap& M, const Stmt* S) {
+  if (!S)
+    return;
+
+  if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
+    const ObjCIvarDecl *D = Ex->getDecl();
+    IvarUsageMap::iterator I = M.find(D);
+    if (I != M.end())
+      I->second = Used;
+    return;
+  }
+
+  // Blocks can reference an instance variable of a class.
+  if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
+    Scan(M, BE->getBody());
+    return;
+  }
+
+  for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I)
+    Scan(M, *I);
+}
+
+static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
+  if (!D)
+    return;
+
+  const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
+
+  if (!ID)
+    return;
+
+  IvarUsageMap::iterator I = M.find(ID);
+  if (I != M.end())
+    I->second = Used;
+}
+
+static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
+  // Scan the methods for accesses.
+  for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
+       E = D->instmeth_end(); I!=E; ++I)
+    Scan(M, (*I)->getBody());
+
+  if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
+    // Scan for @synthesized property methods that act as setters/getters
+    // to an ivar.
+    for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
+         E = ID->propimpl_end(); I!=E; ++I)
+      Scan(M, *I);
+
+    // Scan the associated categories as well.
+    for (const ObjCCategoryDecl *CD =
+          ID->getClassInterface()->getCategoryList(); CD ;
+          CD = CD->getNextClassCategory()) {
+      if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
+        Scan(M, CID);
+    }
+  }
+}
+
+static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
+                 SourceManager &SM) {
+  for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
+       I!=E; ++I)
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
+      SourceLocation L = FD->getLocStart();
+      if (SM.getFileID(L) == FID)
+        Scan(M, FD->getBody());
+    }
+}
+
+void ento::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
+                                BugReporter &BR) {
+
+  const ObjCInterfaceDecl* ID = D->getClassInterface();
+  IvarUsageMap M;
+
+  // Iterate over the ivars.
+  for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
+        E=ID->ivar_end(); I!=E; ++I) {
+
+    const ObjCIvarDecl* ID = *I;
+
+    // Ignore ivars that...
+    // (a) aren't private
+    // (b) explicitly marked unused
+    // (c) are iboutlets
+    // (d) are unnamed bitfields
+    if (ID->getAccessControl() != ObjCIvarDecl::Private ||
+        ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() ||
+        ID->getAttr<IBOutletCollectionAttr>() ||
+        ID->isUnnamedBitfield())
+      continue;
+
+    M[ID] = Unused;
+  }
+
+  if (M.empty())
+    return;
+
+  // Now scan the implementation declaration.
+  Scan(M, D);
+
+  // Any potentially unused ivars?
+  bool hasUnused = false;
+  for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
+    if (I->second == Unused) {
+      hasUnused = true;
+      break;
+    }
+
+  if (!hasUnused)
+    return;
+
+  // We found some potentially unused ivars.  Scan the entire translation unit
+  // for functions inside the @implementation that reference these ivars.
+  // FIXME: In the future hopefully we can just use the lexical DeclContext
+  // to go from the ObjCImplementationDecl to the lexically "nested"
+  // C functions.
+  SourceManager &SM = BR.getSourceManager();
+  Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
+
+  // Find ivars that are unused.
+  for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
+    if (I->second == Unused) {
+      std::string sbuf;
+      llvm::raw_string_ostream os(sbuf);
+      os << "Instance variable '" << I->first << "' in class '" << ID
+         << "' is never used by the methods in its @implementation "
+            "(although it may be used by category methods).";
+
+      BR.EmitBasicReport("Unused instance variable", "Optimization",
+                         os.str(), I->first->getLocation());
+    }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp
new file mode 100644 (file)
index 0000000..2b03dbc
--- /dev/null
@@ -0,0 +1,72 @@
+//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines PointerArithChecker, a builtin checker that checks for
+// pointer arithmetic on locations other than array elements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class PointerArithChecker 
+  : public CheckerVisitor<PointerArithChecker> {
+  BuiltinBug *BT;
+public:
+  PointerArithChecker() : BT(0) {}
+  static void *getTag();
+  void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *PointerArithChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
+                                                 const BinaryOperator *B) {
+  if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add)
+    return;
+
+  const GRState *state = C.getState();
+  SVal LV = state->getSVal(B->getLHS());
+  SVal RV = state->getSVal(B->getRHS());
+
+  const MemRegion *LR = LV.getAsRegion();
+
+  if (!LR || !RV.isConstant())
+    return;
+
+  // If pointer arithmetic is done on variables of non-array type, this often
+  // means behavior rely on memory organization, which is dangerous.
+  if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || 
+      isa<CompoundLiteralRegion>(LR)) {
+
+    if (ExplodedNode *N = C.generateNode()) {
+      if (!BT)
+        BT = new BuiltinBug("Dangerous pointer arithmetic",
+                            "Pointer arithmetic done on non-array variables "
+                            "means reliance on memory layout, which is "
+                            "dangerous.");
+      RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+      R->addRange(B->getSourceRange());
+      C.EmitReport(R);
+    }
+  }
+}
+
+void ento::RegisterPointerArithChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new PointerArithChecker());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp
new file mode 100644 (file)
index 0000000..1ba60f7
--- /dev/null
@@ -0,0 +1,79 @@
+//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines PointerSubChecker, a builtin checker that checks for
+// pointer subtractions on two pointers pointing to different memory chunks. 
+// This check corresponds to CWE-469.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class PointerSubChecker 
+  : public CheckerVisitor<PointerSubChecker> {
+  BuiltinBug *BT;
+public:
+  PointerSubChecker() : BT(0) {}
+  static void *getTag();
+  void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *PointerSubChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
+                                               const BinaryOperator *B) {
+  // When doing pointer subtraction, if the two pointers do not point to the
+  // same memory chunk, emit a warning.
+  if (B->getOpcode() != BO_Sub)
+    return;
+
+  const GRState *state = C.getState();
+  SVal LV = state->getSVal(B->getLHS());
+  SVal RV = state->getSVal(B->getRHS());
+
+  const MemRegion *LR = LV.getAsRegion();
+  const MemRegion *RR = RV.getAsRegion();
+
+  if (!(LR && RR))
+    return;
+
+  const MemRegion *BaseLR = LR->getBaseRegion();
+  const MemRegion *BaseRR = RR->getBaseRegion();
+
+  if (BaseLR == BaseRR)
+    return;
+
+  // Allow arithmetic on different symbolic regions.
+  if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
+    return;
+
+  if (ExplodedNode *N = C.generateNode()) {
+    if (!BT)
+      BT = new BuiltinBug("Pointer subtraction", 
+                          "Subtraction of two pointers that do not point to "
+                          "the same memory chunk may cause incorrect result.");
+    RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+    R->addRange(B->getSourceRange());
+    C.EmitReport(R);
+  }
+}
+
+void ento::RegisterPointerSubChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new PointerSubChecker());
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp
new file mode 100644 (file)
index 0000000..7a91696
--- /dev/null
@@ -0,0 +1,147 @@
+//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines PthreadLockChecker, a simple lock -> unlock checker.  Eventually
+// this shouldn't be registered with ExprEngineInternalChecks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "ExprEngineExperimentalChecks.h"
+#include "llvm/ADT/ImmutableSet.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class PthreadLockChecker
+  : public CheckerVisitor<PthreadLockChecker> {
+  BugType *BT;
+public:
+  PthreadLockChecker() : BT(0) {}
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+  void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+    
+  void AcquireLock(CheckerContext &C, const CallExpr *CE,
+                   SVal lock, bool isTryLock);
+    
+  void ReleaseLock(CheckerContext &C, const CallExpr *CE,
+                    SVal lock);
+
+};
+} // end anonymous namespace
+
+// GDM Entry for tracking lock state.
+namespace { class LockSet {}; }
+namespace clang {
+namespace ento {
+template <> struct GRStateTrait<LockSet> :
+  public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+    static void* GDMIndex() { return PthreadLockChecker::getTag(); }
+};
+} // end GR namespace
+} // end clang namespace
+
+void ento::RegisterPthreadLockChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new PthreadLockChecker());
+}
+
+
+void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
+                                           const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const FunctionTextRegion *R =
+    dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+  
+  if (!R)
+    return;
+  
+  IdentifierInfo *II = R->getDecl()->getIdentifier();
+  if (!II)   // if no identifier, not a simple C function
+    return;
+  llvm::StringRef FName = II->getName();
+  
+  if (FName == "pthread_mutex_lock") {
+    if (CE->getNumArgs() != 1)
+      return;
+    AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
+  }
+  else if (FName == "pthread_mutex_trylock") {
+    if (CE->getNumArgs() != 1)
+      return;
+    AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
+  }  
+  else if (FName == "pthread_mutex_unlock") {
+    if (CE->getNumArgs() != 1)
+      return;
+    ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
+  }
+}
+
+void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
+                                     SVal lock, bool isTryLock) {
+  
+  const MemRegion *lockR = lock.getAsRegion();
+  if (!lockR)
+    return;
+  
+  const GRState *state = C.getState();
+  
+  SVal X = state->getSVal(CE);
+  if (X.isUnknownOrUndef())
+    return;
+  
+  DefinedSVal retVal = cast<DefinedSVal>(X);
+  const GRState *lockSucc = state;
+  
+  if (isTryLock) {
+      // Bifurcate the state, and allow a mode where the lock acquisition fails.
+    const GRState *lockFail;
+    llvm::tie(lockFail, lockSucc) = state->assume(retVal);    
+    assert(lockFail && lockSucc);
+    C.addTransition(C.generateNode(CE, lockFail));
+  }
+  else {
+      // Assume that the return value was 0.
+    lockSucc = state->assume(retVal, false);
+    assert(lockSucc);
+  }
+  
+    // Record that the lock was acquired.  
+  lockSucc = lockSucc->add<LockSet>(lockR);
+  
+  C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
+                  C.getPredecessor());
+}
+
+void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
+                                     SVal lock) {
+
+  const MemRegion *lockR = lock.getAsRegion();
+  if (!lockR)
+    return;
+  
+  const GRState *state = C.getState();
+
+  // Record that the lock was released.  
+  // FIXME: Handle unlocking locks that were never acquired.  This may
+  // require IPA for wrappers.
+  const GRState *unlockState = state->remove<LockSet>(lockR);
+  
+  if (state == unlockState)
+    return;
+  
+  C.addTransition(C.generateNode(CE, unlockState));  
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp
new file mode 100644 (file)
index 0000000..a56c1b6
--- /dev/null
@@ -0,0 +1,95 @@
+//== ReturnPointerRangeChecker.cpp ------------------------------*- 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 ReturnPointerRangeChecker, which is a path-sensitive check
+// which looks for an out-of-bound pointer being returned to callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ReturnPointerRangeChecker : 
+    public CheckerVisitor<ReturnPointerRangeChecker> {      
+  BuiltinBug *BT;
+public:
+    ReturnPointerRangeChecker() : BT(0) {}
+    static void *getTag();
+    void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void ento::RegisterReturnPointerRangeChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new ReturnPointerRangeChecker());
+}
+
+void *ReturnPointerRangeChecker::getTag() {
+  static int x = 0; return &x;
+}
+
+void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
+                                                   const ReturnStmt *RS) {
+  const GRState *state = C.getState();
+
+  const Expr *RetE = RS->getRetValue();
+  if (!RetE)
+    return;
+  SVal V = state->getSVal(RetE);
+  const MemRegion *R = V.getAsRegion();
+
+  const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
+  if (!ER)
+    return;
+
+  DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+  // Zero index is always in bound, this also passes ElementRegions created for
+  // pointer casts.
+  if (Idx.isZeroConstant())
+    return;
+  // FIXME: All of this out-of-bounds checking should eventually be refactored
+  // into a common place.
+
+  DefinedOrUnknownSVal NumElements
+    = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
+                                           ER->getValueType());
+
+  const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
+  const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
+  if (StOutBound && !StInBound) {
+    ExplodedNode *N = C.generateSink(StOutBound);
+
+    if (!N)
+      return;
+  
+    // FIXME: This bug correspond to CWE-466.  Eventually we should have bug
+    // types explicitly reference such exploit categories (when applicable).
+    if (!BT)
+      BT = new BuiltinBug("Return of pointer value outside of expected range",
+           "Returned pointer value points outside the original object "
+           "(potential buffer overflow)");
+
+    // FIXME: It would be nice to eventually make this diagnostic more clear,
+    // e.g., by referencing the original declaration or by saying *why* this
+    // reference is outside the range.
+
+    // Generate a report for this bug.
+    RangedBugReport *report = 
+      new RangedBugReport(*BT, BT->getDescription(), N);
+
+    report->addRange(RetE->getSourceRange());
+    C.EmitReport(report);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp
new file mode 100644 (file)
index 0000000..50ffd32
--- /dev/null
@@ -0,0 +1,69 @@
+//== ReturnUndefChecker.cpp -------------------------------------*- 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 ReturnUndefChecker, which is a path-sensitive
+// check which looks for undefined or garbage values being returned to the
+// caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class ReturnUndefChecker : 
+    public CheckerVisitor<ReturnUndefChecker> {      
+  BuiltinBug *BT;
+public:
+    ReturnUndefChecker() : BT(0) {}
+    static void *getTag();
+    void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void ento::RegisterReturnUndefChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new ReturnUndefChecker());
+}
+
+void *ReturnUndefChecker::getTag() {
+  static int x = 0; return &x;
+}
+
+void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
+                                            const ReturnStmt *RS) {
+  const Expr *RetE = RS->getRetValue();
+  if (!RetE)
+    return;
+  
+  if (!C.getState()->getSVal(RetE).isUndef())
+    return;
+  
+  ExplodedNode *N = C.generateSink();
+
+  if (!N)
+    return;
+  
+  if (!BT)
+    BT = new BuiltinBug("Garbage return value",
+                        "Undefined or garbage value returned to caller");
+    
+  EnhancedBugReport *report = 
+    new EnhancedBugReport(*BT, BT->getDescription(), N);
+
+  report->addRange(RetE->getSourceRange());
+  report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE);
+
+  C.EmitReport(report);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp
new file mode 100644 (file)
index 0000000..1ec5c32
--- /dev/null
@@ -0,0 +1,205 @@
+//=== StackAddrLeakChecker.cpp ------------------------------------*- 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 stack address leak checker, which checks if an invalid 
+// stack address is stored into a global or heap location. See CERT DCL30-C.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+using namespace ento;
+
+namespace {
+class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
+  BuiltinBug *BT_stackleak;
+  BuiltinBug *BT_returnstack;
+
+public:
+  StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
+  static void *getTag() {
+    static int x;
+    return &x;
+  }
+  void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+  void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
+private:
+  void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
+  SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
+                      SourceManager &SM);
+};
+}
+
+void ento::RegisterStackAddrLeakChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new StackAddrLeakChecker());
+}
+
+SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
+                                          const MemRegion *R,
+                                          SourceManager &SM) {
+    // Get the base region, stripping away fields and elements.
+  R = R->getBaseRegion();
+  SourceRange range;
+  os << "Address of ";
+  
+  // Check if the region is a compound literal.
+  if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { 
+    const CompoundLiteralExpr* CL = CR->getLiteralExpr();
+    os << "stack memory associated with a compound literal "
+          "declared on line "
+        << SM.getInstantiationLineNumber(CL->getLocStart())
+        << " returned to caller";    
+    range = CL->getSourceRange();
+  }
+  else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
+    const Expr* ARE = AR->getExpr();
+    SourceLocation L = ARE->getLocStart();
+    range = ARE->getSourceRange();    
+    os << "stack memory allocated by call to alloca() on line "
+       << SM.getInstantiationLineNumber(L);
+  }
+  else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+    const BlockDecl *BD = BR->getCodeRegion()->getDecl();
+    SourceLocation L = BD->getLocStart();
+    range = BD->getSourceRange();
+    os << "stack-allocated block declared on line "
+       << SM.getInstantiationLineNumber(L);
+  }
+  else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+    os << "stack memory associated with local variable '"
+       << VR->getString() << '\'';
+    range = VR->getDecl()->getSourceRange();
+  }
+  else {
+    assert(false && "Invalid region in ReturnStackAddressChecker.");
+  } 
+  
+  return range;
+}
+
+void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
+                                          const Expr *RetE) {
+  ExplodedNode *N = C.generateSink();
+
+  if (!N)
+    return;
+
+  if (!BT_returnstack)
+   BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
+
+  // Generate a report for this bug.
+  llvm::SmallString<512> buf;
+  llvm::raw_svector_ostream os(buf);
+  SourceRange range = GenName(os, R, C.getSourceManager());
+  os << " returned to caller";
+  RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
+  report->addRange(RetE->getSourceRange());
+  if (range.isValid())
+    report->addRange(range);
+
+  C.EmitReport(report);
+}
+
+void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
+                                              const ReturnStmt *RS) {
+  
+  const Expr *RetE = RS->getRetValue();
+  if (!RetE)
+    return;
+  SVal V = C.getState()->getSVal(RetE);
+  const MemRegion *R = V.getAsRegion();
+
+  if (!R || !R->hasStackStorage())
+    return;  
+  
+  if (R->hasStackStorage()) {
+    EmitStackError(C, R, RetE);
+    return;
+  }
+}
+
+void StackAddrLeakChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
+                                       ExprEngine &Eng) {
+  SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
+  const GRState *state = B.getState();
+
+  // Iterate over all bindings to global variables and see if it contains
+  // a memory region in the stack space.
+  class CallBack : public StoreManager::BindingsHandler {
+  private:
+    const StackFrameContext *CurSFC;
+  public:
+    llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
+
+    CallBack(const LocationContext *LCtx)
+      : CurSFC(LCtx->getCurrentStackFrame()) {}
+    
+    bool HandleBinding(StoreManager &SMgr, Store store,
+                       const MemRegion *region, SVal val) {
+      
+      if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
+        return true;
+      
+      const MemRegion *vR = val.getAsRegion();
+      if (!vR)
+        return true;
+      
+      if (const StackSpaceRegion *SSR = 
+          dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
+        // If the global variable holds a location in the current stack frame,
+        // record the binding to emit a warning.
+        if (SSR->getStackFrame() == CurSFC)
+          V.push_back(std::make_pair(region, vR));
+      }
+      
+      return true;
+    }
+  };
+    
+  CallBack cb(B.getPredecessor()->getLocationContext());
+  state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
+
+  if (cb.V.empty())
+    return;
+
+  // Generate an error node.
+  ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+  if (!N)
+    return;
+
+  if (!BT_stackleak)
+    BT_stackleak =
+      new BuiltinBug("Stack address stored into global variable",
+                     "Stack address was saved into a global variable. "
+                     "This is dangerous because the address will become "
+                     "invalid after returning from the function");
+  
+  for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
+    // Generate a report for this bug.
+    llvm::SmallString<512> buf;
+    llvm::raw_svector_ostream os(buf);
+    SourceRange range = GenName(os, cb.V[i].second,
+                                Eng.getContext().getSourceManager());
+    os << " is still referred to by the global variable '";
+    const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
+    os << VR->getDecl()->getNameAsString() 
+       << "' upon returning to the caller.  This will be a dangling reference";
+    RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
+    if (range.isValid())
+      report->addRange(range);
+
+    Eng.getBugReporter().EmitReport(report);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp
new file mode 100644 (file)
index 0000000..a6d1e07
--- /dev/null
@@ -0,0 +1,466 @@
+//===-- StreamChecker.cpp -----------------------------------------*- 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 checkers that model and check stream handling functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineExperimentalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+struct StreamState {
+  enum Kind { Opened, Closed, OpenFailed, Escaped } K;
+  const Stmt *S;
+
+  StreamState(Kind k, const Stmt *s) : K(k), S(s) {}
+
+  bool isOpened() const { return K == Opened; }
+  bool isClosed() const { return K == Closed; }
+  //bool isOpenFailed() const { return K == OpenFailed; }
+  //bool isEscaped() const { return K == Escaped; }
+
+  bool operator==(const StreamState &X) const {
+    return K == X.K && S == X.S;
+  }
+
+  static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
+  static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
+  static StreamState getOpenFailed(const Stmt *s) { 
+    return StreamState(OpenFailed, s); 
+  }
+  static StreamState getEscaped(const Stmt *s) {
+    return StreamState(Escaped, s);
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(K);
+    ID.AddPointer(S);
+  }
+};
+
+class StreamChecker : public CheckerVisitor<StreamChecker> {
+  IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite, 
+                 *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,  
+                 *II_clearerr, *II_feof, *II_ferror, *II_fileno;
+  BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak;
+
+public:
+  StreamChecker() 
+    : II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0), 
+      II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0), 
+      II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0), 
+      BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0), 
+      BT_ResourceLeak(0) {}
+
+  static void *getTag() {
+    static int x;
+    return &x;
+  }
+
+  virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
+  void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
+  void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
+  void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+
+private:
+  void Fopen(CheckerContext &C, const CallExpr *CE);
+  void Tmpfile(CheckerContext &C, const CallExpr *CE);
+  void Fclose(CheckerContext &C, const CallExpr *CE);
+  void Fread(CheckerContext &C, const CallExpr *CE);
+  void Fwrite(CheckerContext &C, const CallExpr *CE);
+  void Fseek(CheckerContext &C, const CallExpr *CE);
+  void Ftell(CheckerContext &C, const CallExpr *CE);
+  void Rewind(CheckerContext &C, const CallExpr *CE);
+  void Fgetpos(CheckerContext &C, const CallExpr *CE);
+  void Fsetpos(CheckerContext &C, const CallExpr *CE);
+  void Clearerr(CheckerContext &C, const CallExpr *CE);
+  void Feof(CheckerContext &C, const CallExpr *CE);
+  void Ferror(CheckerContext &C, const CallExpr *CE);
+  void Fileno(CheckerContext &C, const CallExpr *CE);
+
+  void OpenFileAux(CheckerContext &C, const CallExpr *CE);
+  
+  const GRState *CheckNullStream(SVal SV, const GRState *state, 
+                                 CheckerContext &C);
+  const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state, 
+                                 CheckerContext &C);
+};
+
+} // end anonymous namespace
+
+namespace clang {
+namespace ento {
+  template <>
+  struct GRStateTrait<StreamState> 
+    : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
+    static void *GDMIndex() { return StreamChecker::getTag(); }
+  };
+}
+}
+
+void ento::RegisterStreamChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new StreamChecker());
+}
+
+bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = state->getSVal(Callee);
+  const FunctionDecl *FD = L.getAsFunctionDecl();
+  if (!FD)
+    return false;
+
+  ASTContext &Ctx = C.getASTContext();
+  if (!II_fopen)
+    II_fopen = &Ctx.Idents.get("fopen");
+  if (!II_tmpfile)
+    II_tmpfile = &Ctx.Idents.get("tmpfile");
+  if (!II_fclose)
+    II_fclose = &Ctx.Idents.get("fclose");
+  if (!II_fread)
+    II_fread = &Ctx.Idents.get("fread");
+  if (!II_fwrite)
+    II_fwrite = &Ctx.Idents.get("fwrite");
+  if (!II_fseek)
+    II_fseek = &Ctx.Idents.get("fseek");
+  if (!II_ftell)
+    II_ftell = &Ctx.Idents.get("ftell");
+  if (!II_rewind)
+    II_rewind = &Ctx.Idents.get("rewind");
+  if (!II_fgetpos)
+    II_fgetpos = &Ctx.Idents.get("fgetpos");
+  if (!II_fsetpos)
+    II_fsetpos = &Ctx.Idents.get("fsetpos");
+  if (!II_clearerr)
+    II_clearerr = &Ctx.Idents.get("clearerr");
+  if (!II_feof)
+    II_feof = &Ctx.Idents.get("feof");
+  if (!II_ferror)
+    II_ferror = &Ctx.Idents.get("ferror");
+  if (!II_fileno)
+    II_fileno = &Ctx.Idents.get("fileno");
+
+  if (FD->getIdentifier() == II_fopen) {
+    Fopen(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_tmpfile) {
+    Tmpfile(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fclose) {
+    Fclose(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fread) {
+    Fread(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fwrite) {
+    Fwrite(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fseek) {
+    Fseek(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_ftell) {
+    Ftell(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_rewind) {
+    Rewind(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fgetpos) {
+    Fgetpos(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fsetpos) {
+    Fsetpos(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_clearerr) {
+    Clearerr(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_feof) {
+    Feof(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_ferror) {
+    Ferror(C, CE);
+    return true;
+  }
+  if (FD->getIdentifier() == II_fileno) {
+    Fileno(C, CE);
+    return true;
+  }
+
+  return false;
+}
+
+void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) {
+  OpenFileAux(C, CE);
+}
+
+void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) {
+  OpenFileAux(C, CE);
+}
+
+void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  DefinedSVal RetVal =
+    cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
+  state = state->BindExpr(CE, RetVal);
+  
+  ConstraintManager &CM = C.getConstraintManager();
+  // Bifurcate the state into two: one with a valid FILE* pointer, the other
+  // with a NULL.
+  const GRState *stateNotNull, *stateNull;
+  llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
+  
+  if (SymbolRef Sym = RetVal.getAsSymbol()) {
+    // if RetVal is not NULL, set the symbol's state to Opened.
+    stateNotNull =
+      stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE));
+    stateNull =
+      stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));
+
+    C.addTransition(stateNotNull);
+    C.addTransition(stateNull);
+  }
+}
+
+void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = CheckDoubleClose(CE, C.getState(), C);
+  if (state)
+    C.addTransition(state);
+}
+
+void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
+    return;
+}
+
+void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
+    return;
+}
+
+void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
+    return;
+  // Check the legality of the 'whence' argument of 'fseek'.
+  SVal Whence = state->getSVal(CE->getArg(2));
+  const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
+
+  if (!CI)
+    return;
+
+  int64_t x = CI->getValue().getSExtValue();
+  if (x >= 0 && x <= 2)
+    return;
+
+  if (ExplodedNode *N = C.generateNode(state)) {
+    if (!BT_illegalwhence)
+      BT_illegalwhence = new BuiltinBug("Illegal whence argument",
+                                       "The whence argument to fseek() should be "
+                                       "SEEK_SET, SEEK_END, or SEEK_CUR.");
+    BugReport *R = new BugReport(*BT_illegalwhence, 
+                                BT_illegalwhence->getDescription(), N);
+    C.EmitReport(R);
+  }
+}
+
+void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) {
+  const GRState *state = C.getState();
+  if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
+    return;
+}
+
+const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
+                                    CheckerContext &C) {
+  const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
+  if (!DV)
+    return 0;
+
+  ConstraintManager &CM = C.getConstraintManager();
+  const GRState *stateNotNull, *stateNull;
+  llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+
+  if (!stateNotNull && stateNull) {
+    if (ExplodedNode *N = C.generateSink(stateNull)) {
+      if (!BT_nullfp)
+        BT_nullfp = new BuiltinBug("NULL stream pointer",
+                                     "Stream pointer might be NULL.");
+      BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
+      C.EmitReport(R);
+    }
+    return 0;
+  }
+  return stateNotNull;
+}
+
+const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
+                                               const GRState *state,
+                                               CheckerContext &C) {
+  SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
+  if (!Sym)
+    return state;
+  
+  const StreamState *SS = state->get<StreamState>(Sym);
+
+  // If the file stream is not tracked, return.
+  if (!SS)
+    return state;
+  
+  // Check: Double close a File Descriptor could cause undefined behaviour.
+  // Conforming to man-pages
+  if (SS->isClosed()) {
+    ExplodedNode *N = C.generateSink();
+    if (N) {
+      if (!BT_doubleclose)
+        BT_doubleclose = new BuiltinBug("Double fclose",
+                                        "Try to close a file Descriptor already"
+                                        " closed. Cause undefined behaviour.");
+      BugReport *R = new BugReport(*BT_doubleclose,
+                                   BT_doubleclose->getDescription(), N);
+      C.EmitReport(R);
+    }
+    return NULL;
+  }
+  
+  // Close the File Descriptor.
+  return state->set<StreamState>(Sym, StreamState::getClosed(CE));
+}
+
+void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
+  for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+         E = SymReaper.dead_end(); I != E; ++I) {
+    SymbolRef Sym = *I;
+    const GRState *state = C.getState();
+    const StreamState *SS = state->get<StreamState>(Sym);
+    if (!SS)
+      return;
+
+    if (SS->isOpened()) {
+      ExplodedNode *N = C.generateSink();
+      if (N) {
+        if (!BT_ResourceLeak)
+          BT_ResourceLeak = new BuiltinBug("Resource Leak", 
+                          "Opened File never closed. Potential Resource leak.");
+        BugReport *R = new BugReport(*BT_ResourceLeak, 
+                                     BT_ResourceLeak->getDescription(), N);
+        C.EmitReport(R);
+      }
+    }
+  }
+}
+
+void StreamChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
+                                ExprEngine &Eng) {
+  SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
+  const GRState *state = B.getState();
+  typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
+  SymMap M = state->get<StreamState>();
+  
+  for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+    StreamState SS = I->second;
+    if (SS.isOpened()) {
+      ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+      if (N) {
+        if (!BT_ResourceLeak)
+          BT_ResourceLeak = new BuiltinBug("Resource Leak", 
+                          "Opened File never closed. Potential Resource leak.");
+        BugReport *R = new BugReport(*BT_ResourceLeak, 
+                                     BT_ResourceLeak->getDescription(), N);
+        Eng.getBugReporter().EmitReport(R);
+      }
+    }
+  }
+}
+
+void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+  const Expr *RetE = S->getRetValue();
+  if (!RetE)
+    return;
+  
+  const GRState *state = C.getState();
+  SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
+  
+  if (!Sym)
+    return;
+  
+  const StreamState *SS = state->get<StreamState>(Sym);
+  if(!SS)
+    return;
+
+  if (SS->isOpened())
+    state = state->set<StreamState>(Sym, StreamState::getEscaped(S));
+
+  C.addTransition(state);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp
new file mode 100644 (file)
index 0000000..c0b3b7a
--- /dev/null
@@ -0,0 +1,120 @@
+//=== UndefBranchChecker.cpp -----------------------------------*- 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 UndefBranchChecker, which checks for undefined branch
+// condition.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class UndefBranchChecker : public Checker {
+  BuiltinBug *BT;
+
+  struct FindUndefExpr {
+    GRStateManager& VM;
+    const GRState* St;
+
+    FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
+
+    const Expr* FindExpr(const Expr* Ex) {
+      if (!MatchesCriteria(Ex))
+        return 0;
+
+      for (Stmt::const_child_iterator I = Ex->child_begin(), 
+                                      E = Ex->child_end();I!=E;++I)
+        if (const Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
+          const Expr* E2 = FindExpr(ExI);
+          if (E2) return E2;
+        }
+
+      return Ex;
+    }
+
+    bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); }
+  };
+
+public:
+  UndefBranchChecker() : BT(0) {}
+  static void *getTag();
+  void VisitBranchCondition(BranchNodeBuilder &Builder, ExprEngine &Eng,
+                            const Stmt *Condition, void *tag);
+};
+
+}
+
+void ento::RegisterUndefBranchChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new UndefBranchChecker());
+}
+
+void *UndefBranchChecker::getTag() {
+  static int x;
+  return &x;
+}
+
+void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder, 
+                                              ExprEngine &Eng,
+                                              const Stmt *Condition, void *tag){
+  const GRState *state = Builder.getState();
+  SVal X = state->getSVal(Condition);
+  if (X.isUndef()) {
+    ExplodedNode *N = Builder.generateNode(state, true);
+    if (N) {
+      N->markAsSink();
+      if (!BT)
+        BT = new BuiltinBug("Branch condition evaluates to a garbage value");
+
+      // What's going on here: we want to highlight the subexpression of the
+      // condition that is the most likely source of the "uninitialized
+      // branch condition."  We do a recursive walk of the condition's
+      // subexpressions and roughly look for the most nested subexpression
+      // that binds to Undefined.  We then highlight that expression's range.
+      BlockEdge B = cast<BlockEdge>(N->getLocation());
+      const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
+      assert (Ex && "Block must have a terminator.");
+
+      // Get the predecessor node and check if is a PostStmt with the Stmt
+      // being the terminator condition.  We want to inspect the state
+      // of that node instead because it will contain main information about
+      // the subexpressions.
+      assert (!N->pred_empty());
+
+      // Note: any predecessor will do.  They should have identical state,
+      // since all the BlockEdge did was act as an error sink since the value
+      // had to already be undefined.
+      ExplodedNode *PrevN = *N->pred_begin();
+      ProgramPoint P = PrevN->getLocation();
+      const GRState* St = N->getState();
+
+      if (PostStmt* PS = dyn_cast<PostStmt>(&P))
+        if (PS->getStmt() == Ex)
+          St = PrevN->getState();
+
+      FindUndefExpr FindIt(Eng.getStateManager(), St);
+      Ex = FindIt.FindExpr(Ex);
+
+      // Emit the bug report.
+      EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N);
+      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+      R->addRange(Ex->getSourceRange());
+
+      Eng.getBugReporter().EmitReport(R);
+    }
+
+    Builder.markInfeasible(true);
+    Builder.markInfeasible(false);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp
new file mode 100644 (file)
index 0000000..57e698b
--- /dev/null
@@ -0,0 +1,102 @@
+// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker detects blocks that capture uninitialized values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefCapturedBlockVarChecker
+  : public CheckerVisitor<UndefCapturedBlockVarChecker> {
+ BugType *BT;
+
+public:
+  UndefCapturedBlockVarChecker() : BT(0) {}
+  static void *getTag() { static int tag = 0; return &tag; }
+  void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+};
+} // end anonymous namespace
+
+void ento::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new UndefCapturedBlockVarChecker());
+}
+
+static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
+                                                    const VarDecl *VD){
+  if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S))
+    if (BR->getDecl() == VD)
+      return BR;
+
+  for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
+       I!=E; ++I)
+    if (const Stmt *child = *I) {
+      const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
+      if (BR)
+        return BR;
+    }
+
+  return NULL;
+}
+
+void
+UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
+                                                 const BlockExpr *BE) {
+  if (!BE->hasBlockDeclRefExprs())
+    return;
+
+  const GRState *state = C.getState();
+  const BlockDataRegion *R =
+    cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+  BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+                                            E = R->referenced_vars_end();
+
+  for (; I != E; ++I) {
+    // This VarRegion is the region associated with the block; we need
+    // the one associated with the encompassing context.
+    const VarRegion *VR = *I;
+    const VarDecl *VD = VR->getDecl();
+
+    if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+      continue;
+
+    // Get the VarRegion associated with VD in the local stack frame.
+    const LocationContext *LC = C.getPredecessor()->getLocationContext();
+    VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
+
+    if (state->getSVal(VR).isUndef())
+      if (ExplodedNode *N = C.generateSink()) {
+        if (!BT)
+          BT = new BuiltinBug("Captured block variable is uninitialized");
+
+        // Generate a bug report.
+        llvm::SmallString<128> buf;
+        llvm::raw_svector_ostream os(buf);
+
+        os << "Variable '" << VD->getName() << "' is captured by block with "
+              "a garbage value";
+
+        EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
+        if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
+          R->addRange(Ex->getSourceRange());
+        R->addVisitorCreator(bugreporter::registerFindLastStore, VR);
+        // need location of block
+        C.EmitReport(R);
+      }
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp
new file mode 100644 (file)
index 0000000..91e489b
--- /dev/null
@@ -0,0 +1,87 @@
+//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefResultChecker, a builtin check in ExprEngine that 
+// performs checks for undefined results of non-assignment binary operators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefResultChecker 
+  : public CheckerVisitor<UndefResultChecker> {
+
+  BugType *BT;
+  
+public:
+  UndefResultChecker() : BT(0) {}
+  static void *getTag() { static int tag = 0; return &tag; }
+  void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+} // end anonymous namespace
+
+void ento::RegisterUndefResultChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new UndefResultChecker());
+}
+
+void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C, 
+                                                 const BinaryOperator *B) {
+  const GRState *state = C.getState();
+  if (state->getSVal(B).isUndef()) {
+    // Generate an error node.
+    ExplodedNode *N = C.generateSink();
+    if (!N)
+      return;
+    
+    if (!BT)
+      BT = new BuiltinBug("Result of operation is garbage or undefined");
+
+    llvm::SmallString<256> sbuf;
+    llvm::raw_svector_ostream OS(sbuf);
+    const Expr *Ex = NULL;
+    bool isLeft = true;
+    
+    if (state->getSVal(B->getLHS()).isUndef()) {
+      Ex = B->getLHS()->IgnoreParenCasts();
+      isLeft = true;
+    }
+    else if (state->getSVal(B->getRHS()).isUndef()) {
+      Ex = B->getRHS()->IgnoreParenCasts();
+      isLeft = false;
+    }
+    
+    if (Ex) {
+      OS << "The " << (isLeft ? "left" : "right")
+         << " operand of '"
+         << BinaryOperator::getOpcodeStr(B->getOpcode())
+         << "' is a garbage value";
+    }          
+    else {
+      // Neither operand was undefined, but the result is undefined.
+      OS << "The result of the '"
+         << BinaryOperator::getOpcodeStr(B->getOpcode())
+         << "' expression is undefined";
+    }
+    EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N);
+    if (Ex) {
+      report->addRange(Ex->getSourceRange());
+      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+    }
+    else
+      report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B);
+    C.EmitReport(report);
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp
new file mode 100644 (file)
index 0000000..2cd293b
--- /dev/null
@@ -0,0 +1,57 @@
+//===--- UndefinedArraySubscriptChecker.h ----------------------*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedArraySubscriptChecker, a builtin check in ExprEngine
+// that performs checks for undefined array subscripts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefinedArraySubscriptChecker
+  : public CheckerVisitor<UndefinedArraySubscriptChecker> {
+  BugType *BT;
+public:
+  UndefinedArraySubscriptChecker() : BT(0) {}
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+  void PreVisitArraySubscriptExpr(CheckerContext &C, 
+                                  const ArraySubscriptExpr *A);
+};
+} // end anonymous namespace
+
+void ento::RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new UndefinedArraySubscriptChecker());
+}
+
+void 
+UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, 
+                                                const ArraySubscriptExpr *A) {
+  if (C.getState()->getSVal(A->getIdx()).isUndef()) {
+    if (ExplodedNode *N = C.generateSink()) {
+      if (!BT)
+        BT = new BuiltinBug("Array subscript is undefined");
+
+      // Generate a report for this bug.
+      EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+      R->addRange(A->getIdx()->getSourceRange());
+      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 
+                           A->getIdx());
+      C.EmitReport(R);
+    }
+  }
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp
new file mode 100644 (file)
index 0000000..3146bbd
--- /dev/null
@@ -0,0 +1,94 @@
+//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedAssginmentChecker, a builtin check in ExprEngine that
+// checks for assigning undefined values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefinedAssignmentChecker
+  : public CheckerVisitor<UndefinedAssignmentChecker> {
+  BugType *BT;
+public:
+  UndefinedAssignmentChecker() : BT(0) {}
+  static void *getTag();
+  virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
+                            SVal location, SVal val);
+};
+}
+
+void ento::RegisterUndefinedAssignmentChecker(ExprEngine &Eng){
+  Eng.registerCheck(new UndefinedAssignmentChecker());
+}
+
+void *UndefinedAssignmentChecker::getTag() {
+  static int x = 0;
+  return &x;
+}
+
+void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
+                                              const Stmt *StoreE,
+                                              SVal location,
+                                              SVal val) {
+  if (!val.isUndef())
+    return;
+
+  ExplodedNode *N = C.generateSink();
+
+  if (!N)
+    return;
+
+  const char *str = "Assigned value is garbage or undefined";
+
+  if (!BT)
+    BT = new BuiltinBug(str);
+
+  // Generate a report for this bug.
+  const Expr *ex = 0;
+
+  while (StoreE) {
+    if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
+      if (B->isCompoundAssignmentOp()) {
+        const GRState *state = C.getState();
+        if (state->getSVal(B->getLHS()).isUndef()) {
+          str = "The left expression of the compound assignment is an "
+                "uninitialized value. The computed value will also be garbage";
+          ex = B->getLHS();
+          break;
+        }
+      }
+
+      ex = B->getRHS();
+      break;
+    }
+
+    if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
+      const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+      ex = VD->getInit();
+    }
+
+    break;
+  }
+
+  EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N);
+  if (ex) {
+    R->addRange(ex->getSourceRange());
+    R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
+  }
+  C.EmitReport(R);
+}
+
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp
new file mode 100644 (file)
index 0000000..9092f93
--- /dev/null
@@ -0,0 +1,277 @@
+//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UnixAPIChecker, which is an assortment of checks on calls
+// to various, widely used UNIX/Posix functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include <fcntl.h>
+
+using namespace clang;
+using namespace ento;
+using llvm::Optional;
+
+namespace {
+class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
+  enum SubChecks {
+    OpenFn = 0,
+    PthreadOnceFn = 1,
+    MallocZero = 2,
+    NumChecks
+  };
+
+  BugType *BTypes[NumChecks];
+
+public:
+  Optional<uint64_t> Val_O_CREAT;
+
+public:
+  UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
+  static void *getTag() { static unsigned tag = 0; return &tag; }
+
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} //end anonymous namespace
+
+void ento::RegisterUnixAPIChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new UnixAPIChecker());
+}
+
+//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+static inline void LazyInitialize(BugType *&BT, const char *name) {
+  if (BT)
+    return;
+  BT = new BugType(name, "Unix API");
+}
+
+//===----------------------------------------------------------------------===//
+// "open" (man 2 open)
+//===----------------------------------------------------------------------===//
+
+static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
+                      const CallExpr *CE, BugType *&BT) {
+  // The definition of O_CREAT is platform specific.  We need a better way
+  // of querying this information from the checking environment.
+  if (!UC.Val_O_CREAT.hasValue()) {
+    if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+      UC.Val_O_CREAT = 0x0200;
+    else {
+      // FIXME: We need a more general way of getting the O_CREAT value.
+      // We could possibly grovel through the preprocessor state, but
+      // that would require passing the Preprocessor object to the ExprEngine.
+      return;
+    }
+  }
+
+  LazyInitialize(BT, "Improper use of 'open'");
+
+  // Look at the 'oflags' argument for the O_CREAT flag.
+  const GRState *state = C.getState();
+
+  if (CE->getNumArgs() < 2) {
+    // The frontend should issue a warning for this case, so this is a sanity
+    // check.
+    return;
+  }
+
+  // Now check if oflags has O_CREAT set.
+  const Expr *oflagsEx = CE->getArg(1);
+  const SVal V = state->getSVal(oflagsEx);
+  if (!isa<NonLoc>(V)) {
+    // The case where 'V' can be a location can only be due to a bad header,
+    // so in this case bail out.
+    return;
+  }
+  NonLoc oflags = cast<NonLoc>(V);
+  NonLoc ocreateFlag =
+    cast<NonLoc>(C.getSValBuilder().makeIntVal(UC.Val_O_CREAT.getValue(),
+                                                oflagsEx->getType()));
+  SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
+                                                      oflags, ocreateFlag,
+                                                      oflagsEx->getType());
+  if (maskedFlagsUC.isUnknownOrUndef())
+    return;
+  DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
+
+  // Check if maskedFlags is non-zero.
+  const GRState *trueState, *falseState;
+  llvm::tie(trueState, falseState) = state->assume(maskedFlags);
+
+  // Only emit an error if the value of 'maskedFlags' is properly
+  // constrained;
+  if (!(trueState && !falseState))
+    return;
+
+  if (CE->getNumArgs() < 3) {
+    ExplodedNode *N = C.generateSink(trueState);
+    if (!N)
+      return;
+
+    EnhancedBugReport *report =
+      new EnhancedBugReport(*BT,
+                            "Call to 'open' requires a third argument when "
+                            "the 'O_CREAT' flag is set", N);
+    report->addRange(oflagsEx->getSourceRange());
+    C.EmitReport(report);
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// pthread_once
+//===----------------------------------------------------------------------===//
+
+static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
+                             const CallExpr *CE, BugType *&BT) {
+
+  // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
+  // They can possibly be refactored.
+
+  LazyInitialize(BT, "Improper use of 'pthread_once'");
+
+  if (CE->getNumArgs() < 1)
+    return;
+
+  // Check if the first argument is stack allocated.  If so, issue a warning
+  // because that's likely to be bad news.
+  const GRState *state = C.getState();
+  const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+  if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+    return;
+
+  ExplodedNode *N = C.generateSink(state);
+  if (!N)
+    return;
+
+  llvm::SmallString<256> S;
+  llvm::raw_svector_ostream os(S);
+  os << "Call to 'pthread_once' uses";
+  if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+    os << " the local variable '" << VR->getDecl()->getName() << '\'';
+  else
+    os << " stack allocated memory";
+  os << " for the \"control\" value.  Using such transient memory for "
+  "the control value is potentially dangerous.";
+  if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+    os << "  Perhaps you intended to declare the variable as 'static'?";
+
+  EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+  report->addRange(CE->getArg(0)->getSourceRange());
+  C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
+// "malloc" with allocation size 0
+//===----------------------------------------------------------------------===//
+
+// FIXME: Eventually this should be rolled into the MallocChecker, but this
+// check is more basic and is valuable for widespread use.
+static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
+                            const CallExpr *CE, BugType *&BT) {
+
+  // Sanity check that malloc takes one argument.
+  if (CE->getNumArgs() != 1)
+    return;
+
+  // Check if the allocation size is 0.
+  const GRState *state = C.getState();
+  SVal argVal = state->getSVal(CE->getArg(0));
+
+  if (argVal.isUnknownOrUndef())
+    return;
+  
+  const GRState *trueState, *falseState;
+  llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
+  
+  // Is the value perfectly constrained to zero?
+  if (falseState && !trueState) {
+    ExplodedNode *N = C.generateSink(falseState);
+    if (!N)
+      return;
+    
+    // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
+    // output.
+
+    LazyInitialize(BT, "Undefined allocation of 0 bytes");
+    
+    EnhancedBugReport *report =
+      new EnhancedBugReport(*BT, "Call to 'malloc' has an allocation size"
+                                 " of 0 bytes", N);
+    report->addRange(CE->getArg(0)->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                              CE->getArg(0));
+    C.EmitReport(report);
+    return;
+  }
+  // Assume the the value is non-zero going forward.
+  assert(trueState);
+  if (trueState != state) {
+    C.addTransition(trueState);
+  }
+}
+  
+//===----------------------------------------------------------------------===//
+// Central dispatch function.
+//===----------------------------------------------------------------------===//
+
+typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
+                           const CallExpr *CE, BugType *&BT);
+namespace {
+  class SubCheck {
+    SubChecker SC;
+    UnixAPIChecker *UC;
+    BugType **BT;
+  public:
+    SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
+      BT(&bt) {}
+    SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
+
+    void run(CheckerContext &C, const CallExpr *CE) const {
+      if (SC)
+        SC(C, *UC, CE, *BT);
+    }
+  };
+} // end anonymous namespace
+
+void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+  // Get the callee.  All the functions we care about are C functions
+  // with simple identifiers.
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const FunctionTextRegion *Fn =
+    dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
+
+  if (!Fn)
+    return;
+
+  const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
+  if (!FI)
+    return;
+
+  const SubCheck &SC =
+    llvm::StringSwitch<SubCheck>(FI->getName())
+      .Case("open",
+            SubCheck(CheckOpen, this, BTypes[OpenFn]))
+      .Case("pthread_once",
+            SubCheck(CheckPthreadOnce, this, BTypes[PthreadOnceFn]))
+      .Case("malloc",
+            SubCheck(CheckMallocZero, this, BTypes[MallocZero]))
+      .Default(SubCheck());
+
+  SC.run(C, CE);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp
new file mode 100644 (file)
index 0000000..9883448
--- /dev/null
@@ -0,0 +1,223 @@
+//==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file implements a generalized unreachable code checker using a
+// path-sensitive analysis. We mark any path visited, and then walk the CFG as a
+// post-analysis to determine what was never visited.
+//
+// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
+#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
+#include "ExprEngineExperimentalChecks.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+// The number of CFGBlock pointers we want to reserve memory for. This is used
+// once for each function we analyze.
+#define DEFAULT_CFGBLOCKS 256
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UnreachableCodeChecker : public Checker {
+public:
+  static void *getTag();
+  void VisitEndAnalysis(ExplodedGraph &G,
+                        BugReporter &B,
+                        ExprEngine &Eng);
+private:
+  static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
+  void FindUnreachableEntryPoints(const CFGBlock *CB);
+  static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
+  static inline bool isEmptyCFGBlock(const CFGBlock *CB);
+
+  llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> reachable;
+  llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> visited;
+};
+}
+
+void *UnreachableCodeChecker::getTag() {
+  static int x = 0;
+  return &x;
+}
+
+void ento::RegisterUnreachableCodeChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new UnreachableCodeChecker());
+}
+
+void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
+                                              BugReporter &B,
+                                              ExprEngine &Eng) {
+  // Bail out if we didn't cover all paths
+  if (Eng.hasWorkRemaining())
+    return;
+
+  CFG *C = 0;
+  ParentMap *PM = 0;
+  // Iterate over ExplodedGraph
+  for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
+      I != E; ++I) {
+    const ProgramPoint &P = I->getLocation();
+    const LocationContext *LC = P.getLocationContext();
+
+    // Save the CFG if we don't have it already
+    if (!C)
+      C = LC->getAnalysisContext()->getUnoptimizedCFG();
+    if (!PM)
+      PM = &LC->getParentMap();
+
+    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+      const CFGBlock *CB = BE->getBlock();
+      reachable.insert(CB->getBlockID());
+    }
+  }
+
+  // Bail out if we didn't get the CFG or the ParentMap.
+  if (!C || !PM)
+    return;
+
+  ASTContext &Ctx = B.getContext();
+
+  // Find CFGBlocks that were not covered by any node
+  for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
+    const CFGBlock *CB = *I;
+    // Check if the block is unreachable
+    if (reachable.count(CB->getBlockID()))
+      continue;
+
+    // Check if the block is empty (an artificial block)
+    if (isEmptyCFGBlock(CB))
+      continue;
+
+    // Find the entry points for this block
+    if (!visited.count(CB->getBlockID()))
+      FindUnreachableEntryPoints(CB);
+
+    // This block may have been pruned; check if we still want to report it
+    if (reachable.count(CB->getBlockID()))
+      continue;
+
+    // Check for false positives
+    if (CB->size() > 0 && isInvalidPath(CB, *PM))
+      continue;
+
+    // Special case for __builtin_unreachable.
+    // FIXME: This should be extended to include other unreachable markers,
+    // such as llvm_unreachable.
+    if (!CB->empty()) {
+      CFGElement First = CB->front();
+      if (CFGStmt S = First.getAs<CFGStmt>()) {
+        if (const CallExpr *CE = dyn_cast<CallExpr>(S.getStmt())) {
+          if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
+            continue;
+        }
+      }
+    }
+
+    // We found a block that wasn't covered - find the statement to report
+    SourceRange SR;
+    SourceLocation SL;
+    if (const Stmt *S = getUnreachableStmt(CB)) {
+      SR = S->getSourceRange();
+      SL = S->getLocStart();
+      if (SR.isInvalid() || SL.isInvalid())
+        continue;
+    }
+    else
+      continue;
+
+    // Check if the SourceLocation is in a system header
+    const SourceManager &SM = B.getSourceManager();
+    if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
+      continue;
+
+    B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
+        " executed", SL, SR);
+  }
+}
+
+// Recursively finds the entry point(s) for this dead CFGBlock.
+void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
+  visited.insert(CB->getBlockID());
+
+  for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
+      I != E; ++I) {
+    if (!reachable.count((*I)->getBlockID())) {
+      // If we find an unreachable predecessor, mark this block as reachable so
+      // we don't report this block
+      reachable.insert(CB->getBlockID());
+      if (!visited.count((*I)->getBlockID()))
+        // If we haven't previously visited the unreachable predecessor, recurse
+        FindUnreachableEntryPoints(*I);
+    }
+  }
+}
+
+// Find the Stmt* in a CFGBlock for reporting a warning
+const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
+  for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
+    if (CFGStmt S = I->getAs<CFGStmt>())
+      return S;
+  }
+  if (const Stmt *S = CB->getTerminator())
+    return S;
+  else
+    return 0;
+}
+
+// Determines if the path to this CFGBlock contained an element that infers this
+// block is a false positive. We assume that FindUnreachableEntryPoints has
+// already marked only the entry points to any dead code, so we need only to
+// find the condition that led to this block (the predecessor of this block.)
+// There will never be more than one predecessor.
+bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
+                                           const ParentMap &PM) {
+  // We only expect a predecessor size of 0 or 1. If it is >1, then an external
+  // condition has broken our assumption (for example, a sink being placed by
+  // another check). In these cases, we choose not to report.
+  if (CB->pred_size() > 1)
+    return true;
+
+  // If there are no predecessors, then this block is trivially unreachable
+  if (CB->pred_size() == 0)
+    return false;
+
+  const CFGBlock *pred = *CB->pred_begin();
+
+  // Get the predecessor block's terminator conditon
+  const Stmt *cond = pred->getTerminatorCondition();
+
+  //assert(cond && "CFGBlock's predecessor has a terminator condition");
+  // The previous assertion is invalid in some cases (eg do/while). Leaving
+  // reporting of these situations on at the moment to help triage these cases.
+  if (!cond)
+    return false;
+
+  // Run each of the checks on the conditions
+  if (containsMacro(cond) || containsEnum(cond)
+      || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
+      || containsStmt<SizeOfAlignOfExpr>(cond))
+    return true;
+
+  return false;
+}
+
+// Returns true if the given CFGBlock is empty
+bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
+  return CB->getLabel() == 0       // No labels
+      && CB->size() == 0           // No statements
+      && CB->getTerminator() == 0; // No terminator
+}
diff --git a/lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp
new file mode 100644 (file)
index 0000000..e24521a
--- /dev/null
@@ -0,0 +1,138 @@
+//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines VLASizeChecker, a builtin check in ExprEngine that 
+// performs checks for declaration of VLA of undefined or zero size.
+// In addition, VLASizeChecker is responsible for defining the extent
+// of the MemRegion that represents a VLA.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExprEngineInternalChecks.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/StaticAnalyzer/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
+  BugType *BT_zero;
+  BugType *BT_undef;
+  
+public:
+  VLASizeChecker() : BT_zero(0), BT_undef(0) {}
+  static void *getTag() { static int tag = 0; return &tag; }
+  void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
+};
+} // end anonymous namespace
+
+void ento::RegisterVLASizeChecker(ExprEngine &Eng) {
+  Eng.registerCheck(new VLASizeChecker());
+}
+
+void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+  if (!DS->isSingleDecl())
+    return;
+  
+  const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+  if (!VD)
+    return;
+
+  ASTContext &Ctx = C.getASTContext();
+  const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
+  if (!VLA)
+    return;
+
+  // FIXME: Handle multi-dimensional VLAs.
+  const Expr* SE = VLA->getSizeExpr();
+  const GRState *state = C.getState();
+  SVal sizeV = state->getSVal(SE);
+
+  if (sizeV.isUndef()) {
+    // Generate an error node.
+    ExplodedNode *N = C.generateSink();
+    if (!N)
+      return;
+    
+    if (!BT_undef)
+      BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
+                                "garbage value as its size");
+
+    EnhancedBugReport *report =
+      new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
+    report->addRange(SE->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+    C.EmitReport(report);
+    return;
+  }
+
+  // See if the size value is known. It can't be undefined because we would have
+  // warned about that already.
+  if (sizeV.isUnknown())
+    return;
+  
+  // Check if the size is zero.
+  DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
+
+  const GRState *stateNotZero, *stateZero;
+  llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
+
+  if (stateZero && !stateNotZero) {
+    ExplodedNode* N = C.generateSink(stateZero);
+    if (!BT_zero)
+      BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
+                               "size");
+
+    EnhancedBugReport *report =
+      new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
+    report->addRange(SE->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+    C.EmitReport(report);
+    return;
+  }
+  // From this point on, assume that the size is not zero.
+  state = stateNotZero;
+
+  // VLASizeChecker is responsible for defining the extent of the array being
+  // declared. We do this by multiplying the array length by the element size,
+  // then matching that with the array region's extent symbol.
+
+  // Convert the array length to size_t.
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  QualType SizeTy = Ctx.getSizeType();
+  NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy, 
+                                                         SE->getType()));
+
+  // Get the element size.
+  CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
+  SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
+
+  // Multiply the array length by the element size.
+  SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength,
+                                              cast<NonLoc>(EleSizeVal), SizeTy);
+
+  // Finally, assume that the array's extent matches the given size.
+  const LocationContext *LC = C.getPredecessor()->getLocationContext();
+  DefinedOrUnknownSVal Extent =
+    state->getRegion(VD, LC)->getExtent(svalBuilder);
+  DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
+  DefinedOrUnknownSVal sizeIsKnown =
+    svalBuilder.evalEQ(state, Extent, ArraySize);
+  state = state->assume(sizeIsKnown, true);
+
+  // Assume should not fail at this point.
+  assert(state);
+
+  // Remember our assumptions!
+  C.addTransition(state);
+}
diff --git a/lib/StaticAnalyzer/EntoSA/CoreEngine.cpp b/lib/StaticAnalyzer/EntoSA/CoreEngine.cpp
new file mode 100644 (file)
index 0000000..a23c7f9
--- /dev/null
@@ -0,0 +1,809 @@
+//==- CoreEngine.cpp - Path-Sensitive Dataflow Engine ------------*- 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 a generic engine for intraprocedural, path-sensitive,
+//  dataflow analysis via graph reachability engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/Index/TranslationUnit.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
+#include <queue>
+
+using llvm::cast;
+using llvm::isa;
+using namespace clang;
+using namespace ento;
+
+// This should be removed in the future.
+namespace clang {
+namespace ento {
+TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+                                  const LangOptions& lopts);
+}
+}
+
+//===----------------------------------------------------------------------===//
+// Worklist classes for exploration of reachable states.
+//===----------------------------------------------------------------------===//
+
+WorkList::Visitor::~Visitor() {}
+
+namespace {
+class DFS : public WorkList {
+  llvm::SmallVector<WorkListUnit,20> Stack;
+public:
+  virtual bool hasWork() const {
+    return !Stack.empty();
+  }
+
+  virtual void Enqueue(const WorkListUnit& U) {
+    Stack.push_back(U);
+  }
+
+  virtual WorkListUnit Dequeue() {
+    assert (!Stack.empty());
+    const WorkListUnit& U = Stack.back();
+    Stack.pop_back(); // This technically "invalidates" U, but we are fine.
+    return U;
+  }
+  
+  virtual bool VisitItemsInWorkList(Visitor &V) {
+    for (llvm::SmallVectorImpl<WorkListUnit>::iterator
+         I = Stack.begin(), E = Stack.end(); I != E; ++I) {
+      if (V.Visit(*I))
+        return true;
+    }
+    return false;
+  }
+};
+
+class BFS : public WorkList {
+  std::deque<WorkListUnit> Queue;
+public:
+  virtual bool hasWork() const {
+    return !Queue.empty();
+  }
+
+  virtual void Enqueue(const WorkListUnit& U) {
+    Queue.push_front(U);
+  }
+
+  virtual WorkListUnit Dequeue() {
+    WorkListUnit U = Queue.front();
+    Queue.pop_front();
+    return U;
+  }
+  
+  virtual bool VisitItemsInWorkList(Visitor &V) {
+    for (std::deque<WorkListUnit>::iterator
+         I = Queue.begin(), E = Queue.end(); I != E; ++I) {
+      if (V.Visit(*I))
+        return true;
+    }
+    return false;
+  }
+};
+
+} // end anonymous namespace
+
+// Place the dstor for WorkList here because it contains virtual member
+// functions, and we the code for the dstor generated in one compilation unit.
+WorkList::~WorkList() {}
+
+WorkList *WorkList::MakeDFS() { return new DFS(); }
+WorkList *WorkList::MakeBFS() { return new BFS(); }
+
+namespace {
+  class BFSBlockDFSContents : public WorkList {
+    std::deque<WorkListUnit> Queue;
+    llvm::SmallVector<WorkListUnit,20> Stack;
+  public:
+    virtual bool hasWork() const {
+      return !Queue.empty() || !Stack.empty();
+    }
+
+    virtual void Enqueue(const WorkListUnit& U) {
+      if (isa<BlockEntrance>(U.getNode()->getLocation()))
+        Queue.push_front(U);
+      else
+        Stack.push_back(U);
+    }
+
+    virtual WorkListUnit Dequeue() {
+      // Process all basic blocks to completion.
+      if (!Stack.empty()) {
+        const WorkListUnit& U = Stack.back();
+        Stack.pop_back(); // This technically "invalidates" U, but we are fine.
+        return U;
+      }
+
+      assert(!Queue.empty());
+      // Don't use const reference.  The subsequent pop_back() might make it
+      // unsafe.
+      WorkListUnit U = Queue.front();
+      Queue.pop_front();
+      return U;
+    }
+    virtual bool VisitItemsInWorkList(Visitor &V) {
+      for (llvm::SmallVectorImpl<WorkListUnit>::iterator
+           I = Stack.begin(), E = Stack.end(); I != E; ++I) {
+        if (V.Visit(*I))
+          return true;
+      }
+      for (std::deque<WorkListUnit>::iterator
+           I = Queue.begin(), E = Queue.end(); I != E; ++I) {
+        if (V.Visit(*I))
+          return true;
+      }
+      return false;
+    }
+
+  };
+} // end anonymous namespace
+
+WorkList* WorkList::MakeBFSBlockDFSContents() {
+  return new BFSBlockDFSContents();
+}
+
+//===----------------------------------------------------------------------===//
+// Core analysis engine.
+//===----------------------------------------------------------------------===//
+
+/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
+bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
+                                   const GRState *InitState) {
+
+  if (G->num_roots() == 0) { // Initialize the analysis by constructing
+    // the root if none exists.
+
+    const CFGBlock* Entry = &(L->getCFG()->getEntry());
+
+    assert (Entry->empty() &&
+            "Entry block must be empty.");
+
+    assert (Entry->succ_size() == 1 &&
+            "Entry block must have 1 successor.");
+
+    // Get the solitary successor.
+    const CFGBlock* Succ = *(Entry->succ_begin());
+
+    // Construct an edge representing the
+    // starting location in the function.
+    BlockEdge StartLoc(Entry, Succ, L);
+
+    // Set the current block counter to being empty.
+    WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
+
+    if (!InitState)
+      // Generate the root.
+      generateNode(StartLoc, getInitialState(L), 0);
+    else
+      generateNode(StartLoc, InitState, 0);
+  }
+
+  // Check if we have a steps limit
+  bool UnlimitedSteps = Steps == 0;
+
+  while (WList->hasWork()) {
+    if (!UnlimitedSteps) {
+      if (Steps == 0)
+        break;
+      --Steps;
+    }
+
+    const WorkListUnit& WU = WList->Dequeue();
+
+    // Set the current block counter.
+    WList->setBlockCounter(WU.getBlockCounter());
+
+    // Retrieve the node.
+    ExplodedNode* Node = WU.getNode();
+
+    // Dispatch on the location type.
+    switch (Node->getLocation().getKind()) {
+      case ProgramPoint::BlockEdgeKind:
+        HandleBlockEdge(cast<BlockEdge>(Node->getLocation()), Node);
+        break;
+
+      case ProgramPoint::BlockEntranceKind:
+        HandleBlockEntrance(cast<BlockEntrance>(Node->getLocation()), Node);
+        break;
+
+      case ProgramPoint::BlockExitKind:
+        assert (false && "BlockExit location never occur in forward analysis.");
+        break;
+
+      case ProgramPoint::CallEnterKind:
+        HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(), 
+                        WU.getIndex(), Node);
+        break;
+
+      case ProgramPoint::CallExitKind:
+        HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
+        break;
+
+      default:
+        assert(isa<PostStmt>(Node->getLocation()) || 
+               isa<PostInitializer>(Node->getLocation()));
+        HandlePostStmt(WU.getBlock(), WU.getIndex(), Node);
+        break;
+    }
+  }
+
+  SubEng.ProcessEndWorklist(hasWorkRemaining());
+  return WList->hasWork();
+}
+
+void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, 
+                                                   unsigned Steps,
+                                                   const GRState *InitState, 
+                                                   ExplodedNodeSet &Dst) {
+  ExecuteWorkList(L, Steps, InitState);
+  for (llvm::SmallVectorImpl<ExplodedNode*>::iterator I = G->EndNodes.begin(), 
+                                           E = G->EndNodes.end(); I != E; ++I) {
+    Dst.Add(*I);
+  }
+}
+
+void CoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
+                                   unsigned Index, ExplodedNode *Pred) {
+  CallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), 
+                                 L.getCalleeContext(), Block, Index);
+  ProcessCallEnter(Builder);
+}
+
+void CoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
+  CallExitNodeBuilder Builder(*this, Pred);
+  ProcessCallExit(Builder);
+}
+
+void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
+
+  const CFGBlock* Blk = L.getDst();
+
+  // Check if we are entering the EXIT block.
+  if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
+
+    assert (L.getLocationContext()->getCFG()->getExit().size() == 0
+            && "EXIT block cannot contain Stmts.");
+
+    // Process the final state transition.
+    EndPathNodeBuilder Builder(Blk, Pred, this);
+    ProcessEndPath(Builder);
+
+    // This path is done. Don't enqueue any more nodes.
+    return;
+  }
+
+  // FIXME: Should we allow ProcessBlockEntrance to also manipulate state?
+
+  if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter()))
+    generateNode(BlockEntrance(Blk, Pred->getLocationContext()),
+                 Pred->State, Pred);
+  else {
+    blocksAborted.push_back(std::make_pair(L, Pred));
+  }
+}
+
+void CoreEngine::HandleBlockEntrance(const BlockEntrance& L,
+                                       ExplodedNode* Pred) {
+
+  // Increment the block counter.
+  BlockCounter Counter = WList->getBlockCounter();
+  Counter = BCounterFactory.IncrementCount(Counter, 
+                             Pred->getLocationContext()->getCurrentStackFrame(),
+                                           L.getBlock()->getBlockID());
+  WList->setBlockCounter(Counter);
+
+  // Process the entrance of the block.
+  if (CFGElement E = L.getFirstElement()) {
+    StmtNodeBuilder Builder(L.getBlock(), 0, Pred, this,
+                              SubEng.getStateManager());
+    ProcessElement(E, Builder);
+  }
+  else
+    HandleBlockExit(L.getBlock(), Pred);
+}
+
+void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) {
+
+  if (const Stmt* Term = B->getTerminator()) {
+    switch (Term->getStmtClass()) {
+      default:
+        assert(false && "Analysis for this terminator not implemented.");
+        break;
+
+      case Stmt::BinaryOperatorClass: // '&&' and '||'
+        HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
+        return;
+
+      case Stmt::ConditionalOperatorClass:
+        HandleBranch(cast<ConditionalOperator>(Term)->getCond(), Term, B, Pred);
+        return;
+
+        // FIXME: Use constant-folding in CFG construction to simplify this
+        // case.
+
+      case Stmt::ChooseExprClass:
+        HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
+        return;
+
+      case Stmt::DoStmtClass:
+        HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
+        return;
+
+      case Stmt::ForStmtClass:
+        HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
+        return;
+
+      case Stmt::ContinueStmtClass:
+      case Stmt::BreakStmtClass:
+      case Stmt::GotoStmtClass:
+        break;
+
+      case Stmt::IfStmtClass:
+        HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
+        return;
+
+      case Stmt::IndirectGotoStmtClass: {
+        // Only 1 successor: the indirect goto dispatch block.
+        assert (B->succ_size() == 1);
+
+        IndirectGotoNodeBuilder
+           builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
+                   *(B->succ_begin()), this);
+
+        ProcessIndirectGoto(builder);
+        return;
+      }
+
+      case Stmt::ObjCForCollectionStmtClass: {
+        // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
+        //
+        //  (1) inside a basic block, which represents the binding of the
+        //      'element' variable to a value.
+        //  (2) in a terminator, which represents the branch.
+        //
+        // For (1), subengines will bind a value (i.e., 0 or 1) indicating
+        // whether or not collection contains any more elements.  We cannot
+        // just test to see if the element is nil because a container can
+        // contain nil elements.
+        HandleBranch(Term, Term, B, Pred);
+        return;
+      }
+
+      case Stmt::SwitchStmtClass: {
+        SwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(),
+                                    this);
+
+        ProcessSwitch(builder);
+        return;
+      }
+
+      case Stmt::WhileStmtClass:
+        HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
+        return;
+    }
+  }
+
+  assert (B->succ_size() == 1 &&
+          "Blocks with no terminator should have at most 1 successor.");
+
+  generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
+               Pred->State, Pred);
+}
+
+void CoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term, 
+                                const CFGBlock * B, ExplodedNode* Pred) {
+  assert (B->succ_size() == 2);
+
+  BranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1),
+                              Pred, this);
+
+  ProcessBranch(Cond, Term, Builder);
+}
+
+void CoreEngine::HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, 
+                                  ExplodedNode* Pred) {
+  assert (!B->empty());
+
+  if (StmtIdx == B->size())
+    HandleBlockExit(B, Pred);
+  else {
+    StmtNodeBuilder Builder(B, StmtIdx, Pred, this,
+                              SubEng.getStateManager());
+    ProcessElement((*B)[StmtIdx], Builder);
+  }
+}
+
+/// generateNode - Utility method to generate nodes, hook up successors,
+///  and add nodes to the worklist.
+void CoreEngine::generateNode(const ProgramPoint& Loc,
+                              const GRState* State, ExplodedNode* Pred) {
+
+  bool IsNew;
+  ExplodedNode* Node = G->getNode(Loc, State, &IsNew);
+
+  if (Pred)
+    Node->addPredecessor(Pred, *G);  // Link 'Node' with its predecessor.
+  else {
+    assert (IsNew);
+    G->addRoot(Node);  // 'Node' has no predecessor.  Make it a root.
+  }
+
+  // Only add 'Node' to the worklist if it was freshly generated.
+  if (IsNew) WList->Enqueue(Node);
+}
+
+StmtNodeBuilder::StmtNodeBuilder(const CFGBlock* b, unsigned idx,
+                                     ExplodedNode* N, CoreEngine* e,
+                                     GRStateManager &mgr)
+  : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr),
+    PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false),
+    PointKind(ProgramPoint::PostStmtKind), Tag(0) {
+  Deferred.insert(N);
+  CleanedState = Pred->getState();
+}
+
+StmtNodeBuilder::~StmtNodeBuilder() {
+  for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
+    if (!(*I)->isSink())
+      GenerateAutoTransition(*I);
+}
+
+void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
+  assert (!N->isSink());
+
+  // Check if this node entered a callee.
+  if (isa<CallEnter>(N->getLocation())) {
+    // Still use the index of the CallExpr. It's needed to create the callee
+    // StackFrameContext.
+    Eng.WList->Enqueue(N, &B, Idx);
+    return;
+  }
+
+  // Do not create extra nodes. Move to the next CFG element.
+  if (isa<PostInitializer>(N->getLocation())) {
+    Eng.WList->Enqueue(N, &B, Idx+1);
+    return;
+  }
+
+  PostStmt Loc(getStmt(), N->getLocationContext());
+
+  if (Loc == N->getLocation()) {
+    // Note: 'N' should be a fresh node because otherwise it shouldn't be
+    // a member of Deferred.
+    Eng.WList->Enqueue(N, &B, Idx+1);
+    return;
+  }
+
+  bool IsNew;
+  ExplodedNode* Succ = Eng.G->getNode(Loc, N->State, &IsNew);
+  Succ->addPredecessor(N, *Eng.G);
+
+  if (IsNew)
+    Eng.WList->Enqueue(Succ, &B, Idx+1);
+}
+
+ExplodedNode* StmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, 
+                                          ExplodedNode* Pred, const GRState* St,
+                                          ProgramPoint::Kind K) {
+
+  ExplodedNode* N = generateNode(S, St, Pred, K);
+
+  if (N) {
+    if (BuildSinks)
+      N->markAsSink();
+    else
+      Dst.Add(N);
+  }
+  
+  return N;
+}
+
+static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
+                                    const LocationContext *LC, const void *tag){
+  switch (K) {
+    default:
+      assert(false && "Unhandled ProgramPoint kind");    
+    case ProgramPoint::PreStmtKind:
+      return PreStmt(S, LC, tag);
+    case ProgramPoint::PostStmtKind:
+      return PostStmt(S, LC, tag);
+    case ProgramPoint::PreLoadKind:
+      return PreLoad(S, LC, tag);
+    case ProgramPoint::PostLoadKind:
+      return PostLoad(S, LC, tag);
+    case ProgramPoint::PreStoreKind:
+      return PreStore(S, LC, tag);
+    case ProgramPoint::PostStoreKind:
+      return PostStore(S, LC, tag);
+    case ProgramPoint::PostLValueKind:
+      return PostLValue(S, LC, tag);
+    case ProgramPoint::PostPurgeDeadSymbolsKind:
+      return PostPurgeDeadSymbols(S, LC, tag);
+  }
+}
+
+ExplodedNode*
+StmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
+                                        ExplodedNode* Pred,
+                                        ProgramPoint::Kind K,
+                                        const void *tag) {
+  
+  const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
+  return generateNodeInternal(L, state, Pred);
+}
+
+ExplodedNode*
+StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc,
+                                        const GRState* State,
+                                        ExplodedNode* Pred) {
+  bool IsNew;
+  ExplodedNode* N = Eng.G->getNode(Loc, State, &IsNew);
+  N->addPredecessor(Pred, *Eng.G);
+  Deferred.erase(Pred);
+
+  if (IsNew) {
+    Deferred.insert(N);
+    return N;
+  }
+
+  return NULL;
+}
+
+ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State,
+                                                bool branch) {
+
+  // If the branch has been marked infeasible we should not generate a node.
+  if (!isFeasible(branch))
+    return NULL;
+
+  bool IsNew;
+
+  ExplodedNode* Succ =
+    Eng.G->getNode(BlockEdge(Src,branch ? DstT:DstF,Pred->getLocationContext()),
+                   State, &IsNew);
+
+  Succ->addPredecessor(Pred, *Eng.G);
+
+  if (branch)
+    GeneratedTrue = true;
+  else
+    GeneratedFalse = true;
+
+  if (IsNew) {
+    Deferred.push_back(Succ);
+    return Succ;
+  }
+
+  return NULL;
+}
+
+BranchNodeBuilder::~BranchNodeBuilder() {
+  if (!GeneratedTrue) generateNode(Pred->State, true);
+  if (!GeneratedFalse) generateNode(Pred->State, false);
+
+  for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
+    if (!(*I)->isSink()) Eng.WList->Enqueue(*I);
+}
+
+
+ExplodedNode*
+IndirectGotoNodeBuilder::generateNode(const iterator& I, const GRState* St,
+                                        bool isSink) {
+  bool IsNew;
+
+  ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
+                                      Pred->getLocationContext()), St, &IsNew);
+
+  Succ->addPredecessor(Pred, *Eng.G);
+
+  if (IsNew) {
+
+    if (isSink)
+      Succ->markAsSink();
+    else
+      Eng.WList->Enqueue(Succ);
+
+    return Succ;
+  }
+
+  return NULL;
+}
+
+
+ExplodedNode*
+SwitchNodeBuilder::generateCaseStmtNode(const iterator& I, const GRState* St){
+
+  bool IsNew;
+
+  ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, I.getBlock(),
+                                       Pred->getLocationContext()), St, &IsNew);
+  Succ->addPredecessor(Pred, *Eng.G);
+
+  if (IsNew) {
+    Eng.WList->Enqueue(Succ);
+    return Succ;
+  }
+
+  return NULL;
+}
+
+
+ExplodedNode*
+SwitchNodeBuilder::generateDefaultCaseNode(const GRState* St, bool isSink) {
+
+  // Get the block for the default case.
+  assert (Src->succ_rbegin() != Src->succ_rend());
+  CFGBlock* DefaultBlock = *Src->succ_rbegin();
+
+  bool IsNew;
+
+  ExplodedNode* Succ = Eng.G->getNode(BlockEdge(Src, DefaultBlock,
+                                       Pred->getLocationContext()), St, &IsNew);
+  Succ->addPredecessor(Pred, *Eng.G);
+
+  if (IsNew) {
+    if (isSink)
+      Succ->markAsSink();
+    else
+      Eng.WList->Enqueue(Succ);
+
+    return Succ;
+  }
+
+  return NULL;
+}
+
+EndPathNodeBuilder::~EndPathNodeBuilder() {
+  // Auto-generate an EOP node if one has not been generated.
+  if (!HasGeneratedNode) {
+    // If we are in an inlined call, generate CallExit node.
+    if (Pred->getLocationContext()->getParent())
+      GenerateCallExitNode(Pred->State);
+    else
+      generateNode(Pred->State);
+  }
+}
+
+ExplodedNode*
+EndPathNodeBuilder::generateNode(const GRState* State, const void *tag,
+                                   ExplodedNode* P) {
+  HasGeneratedNode = true;
+  bool IsNew;
+
+  ExplodedNode* Node = Eng.G->getNode(BlockEntrance(&B,
+                               Pred->getLocationContext(), tag), State, &IsNew);
+
+  Node->addPredecessor(P ? P : Pred, *Eng.G);
+
+  if (IsNew) {
+    Eng.G->addEndOfPath(Node);
+    return Node;
+  }
+
+  return NULL;
+}
+
+void EndPathNodeBuilder::GenerateCallExitNode(const GRState *state) {
+  HasGeneratedNode = true;
+  // Create a CallExit node and enqueue it.
+  const StackFrameContext *LocCtx
+                         = cast<StackFrameContext>(Pred->getLocationContext());
+  const Stmt *CE = LocCtx->getCallSite();
+
+  // Use the the callee location context.
+  CallExit Loc(CE, LocCtx);
+
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(Pred, *Eng.G);
+
+  if (isNew)
+    Eng.WList->Enqueue(Node);
+}
+                                                
+
+void CallEnterNodeBuilder::generateNode(const GRState *state) {
+  // Check if the callee is in the same translation unit.
+  if (CalleeCtx->getTranslationUnit() != 
+      Pred->getLocationContext()->getTranslationUnit()) {
+    // Create a new engine. We must be careful that the new engine should not
+    // reference data structures owned by the old engine.
+
+    AnalysisManager &OldMgr = Eng.SubEng.getAnalysisManager();
+    
+    // Get the callee's translation unit.
+    idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit();
+
+    // Create a new AnalysisManager with components of the callee's
+    // TranslationUnit.
+    // The Diagnostic is actually shared when we create ASTUnits from AST files.
+    AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), 
+                         OldMgr.getLangOptions(), 
+                         OldMgr.getPathDiagnosticClient(),
+                         OldMgr.getStoreManagerCreator(),
+                         OldMgr.getConstraintManagerCreator(),
+                         OldMgr.getIndexer(),
+                         OldMgr.getMaxNodes(), OldMgr.getMaxVisit(),
+                         OldMgr.shouldVisualizeGraphviz(),
+                         OldMgr.shouldVisualizeUbigraph(),
+                         OldMgr.shouldPurgeDead(),
+                         OldMgr.shouldEagerlyAssume(),
+                         OldMgr.shouldTrimGraph(),
+                         OldMgr.shouldInlineCall(),
+                     OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(),
+                     OldMgr.getAnalysisContextManager().getAddImplicitDtors(),
+                     OldMgr.getAnalysisContextManager().getAddInitializers());
+    llvm::OwningPtr<TransferFuncs> TF(MakeCFRefCountTF(AMgr.getASTContext(),
+                                                         /* GCEnabled */ false,
+                                                        AMgr.getLangOptions()));
+    // Create the new engine.
+    ExprEngine NewEng(AMgr, TF.take());
+
+    // Create the new LocationContext.
+    AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(), 
+                                               CalleeCtx->getTranslationUnit());
+    const StackFrameContext *OldLocCtx = CalleeCtx;
+    const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx, 
+                                               OldLocCtx->getParent(),
+                                               OldLocCtx->getCallSite(),
+                                               OldLocCtx->getCallSiteBlock(), 
+                                               OldLocCtx->getIndex());
+
+    // Now create an initial state for the new engine.
+    const GRState *NewState = NewEng.getStateManager().MarshalState(state,
+                                                                    NewLocCtx);
+    ExplodedNodeSet ReturnNodes;
+    NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(), 
+                                           NewState, ReturnNodes);
+    return;
+  }
+
+  // Get the callee entry block.
+  const CFGBlock *Entry = &(CalleeCtx->getCFG()->getEntry());
+  assert(Entry->empty());
+  assert(Entry->succ_size() == 1);
+
+  // Get the solitary successor.
+  const CFGBlock *SuccB = *(Entry->succ_begin());
+
+  // Construct an edge representing the starting location in the callee.
+  BlockEdge Loc(Entry, SuccB, CalleeCtx);
+
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+
+  if (isNew)
+    Eng.WList->Enqueue(Node);
+}
+
+void CallExitNodeBuilder::generateNode(const GRState *state) {
+  // Get the callee's location context.
+  const StackFrameContext *LocCtx 
+                         = cast<StackFrameContext>(Pred->getLocationContext());
+  // When exiting an implicit automatic obj dtor call, the callsite is the Stmt
+  // that triggers the dtor.
+  PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+  if (isNew)
+    Eng.WList->Enqueue(Node, LocCtx->getCallSiteBlock(),
+                       LocCtx->getIndex() + 1);
+}
similarity index 99%
rename from lib/EntoSA/Environment.cpp
rename to lib/StaticAnalyzer/EntoSA/Environment.cpp
index eecbabbb2e37f571c1ea58dfc6259af8a50389f2..1c74352d2c9d27ebd4cf4ed8d33ff9cbfc81ed68 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "clang/Analysis/AnalysisContext.h"
 #include "clang/Analysis/CFG.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 
 using namespace clang;
 using namespace ento;
similarity index 98%
rename from lib/EntoSA/ExplodedGraph.cpp
rename to lib/StaticAnalyzer/EntoSA/ExplodedGraph.cpp
index ec66ba60280cc6cb9cf5bbab519a6dc7186018cd..4c4612fab5e760793e916dc26dbf1fd7e6f2e90a 100644 (file)
@@ -12,8 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/ExplodedGraph.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "clang/AST/Stmt.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/DenseMap.h"
similarity index 99%
rename from lib/EntoSA/FlatStore.cpp
rename to lib/StaticAnalyzer/EntoSA/FlatStore.cpp
index 8ded4d16b6528c97bc5910e3c973b9f4f3a419ee..1558db748346512a3d42798d94615aa7a0a618ea 100644 (file)
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "llvm/ADT/ImmutableIntervalMap.h"
 #include "llvm/Support/ErrorHandling.h"
 
similarity index 98%
rename from lib/EntoSA/GRState.cpp
rename to lib/StaticAnalyzer/EntoSA/GRState.cpp
index 62396230ff72328c0e66d5fcdbe255f93796619d..12c8968367ec232335a7a0b016f37912a495b027 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "clang/Analysis/CFG.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/SubEngine.h"
-#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
similarity index 99%
rename from lib/EntoSA/HTMLDiagnostics.cpp
rename to lib/StaticAnalyzer/EntoSA/HTMLDiagnostics.cpp
index a0d338ae1e689c468f053bef65e7739c8925df22..659c32d58d47fa7b36936df2dab0a0894c8af3e1 100644 (file)
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathDiagnosticClients.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/Basic/SourceManager.h"
similarity index 93%
rename from lib/EntoSA/Makefile
rename to lib/StaticAnalyzer/EntoSA/Makefile
index 967813869548ca3a7e28bce7d637569163363adb..08ace28e35c7e2cae195a173e653774b3fb185bf 100644 (file)
@@ -12,7 +12,7 @@
 ##===----------------------------------------------------------------------===##
 
 CLANG_LEVEL := ../..
-LIBRARYNAME := clangEntoCore
+LIBRARYNAME := clangStaticAnalyzerCore
 PARALLEL_DIRS := Checkers
 
 include $(CLANG_LEVEL)/Makefile
similarity index 93%
rename from lib/EntoSA/ManagerRegistry.cpp
rename to lib/StaticAnalyzer/EntoSA/ManagerRegistry.cpp
index 99b7a707481b62722d2b3ce389bb3306700b1603..3f9ed61db74a6fbb7daeffdcd6632b47e049384a 100644 (file)
@@ -11,7 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/ManagerRegistry.h"
+#include "clang/StaticAnalyzer/ManagerRegistry.h"
 
 using namespace clang;
 using namespace ento;
similarity index 99%
rename from lib/EntoSA/MemRegion.cpp
rename to lib/StaticAnalyzer/EntoSA/MemRegion.cpp
index ff0f34044e76b11db48c006867430d39fe5296d1..e465224f4270546e38901ee21df30f7e4907c655 100644 (file)
@@ -13,8 +13,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
-#include "clang/EntoSA/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
 #include "clang/Analysis/AnalysisContext.h"
 #include "clang/Analysis/Support/BumpVector.h"
 #include "clang/AST/CharUnits.h"
similarity index 99%
rename from lib/EntoSA/PathDiagnostic.cpp
rename to lib/StaticAnalyzer/EntoSA/PathDiagnostic.cpp
index bf8c8b0d3d9d9ebf0fa9cdcb71e2524d1ceef508..f05dec820d358e5d79bae93df887e6f64fca14fd 100644 (file)
@@ -11,7 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclObjC.h"
similarity index 99%
rename from lib/EntoSA/PlistDiagnostics.cpp
rename to lib/StaticAnalyzer/EntoSA/PlistDiagnostics.cpp
index 6e54d494c5dcc0c68edd0dc3bcb8a62beb4a72fa..ecc0cff5c3f2f530287b2b002906694eb4f79855 100644 (file)
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathDiagnosticClients.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Lex/Preprocessor.h"
similarity index 98%
rename from lib/EntoSA/RangeConstraintManager.cpp
rename to lib/StaticAnalyzer/EntoSA/RangeConstraintManager.cpp
index 5c2d674515b4664f9e795ded75e7381e8edcb3fa..c89fa50b166a791290a267da685beb0f06b17d2a 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "SimpleConstraintManager.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/TransferFuncs.h"
-#include "clang/EntoSA/ManagerRegistry.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/ManagerRegistry.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
similarity index 99%
rename from lib/EntoSA/RegionStore.cpp
rename to lib/StaticAnalyzer/EntoSA/RegionStore.cpp
index 49795c689279fb68373bea8875bddc430c3e3256..def1b43f345339adf0d6078c94b6f6c497f1e1ed 100644 (file)
@@ -20,9 +20,9 @@
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/AnalysisContext.h"
 #include "clang/Basic/TargetInfo.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/GRStateTrait.h"
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/ImmutableMap.h"
 #include "llvm/ADT/Optional.h"
similarity index 97%
rename from lib/EntoSA/SValBuilder.cpp
rename to lib/StaticAnalyzer/EntoSA/SValBuilder.cpp
index c4efaae90660ab910ada4a22d97ccb37b2f4544f..f87fb7ee1e4f45fa18e05854d10d68bc874b9190 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
-#include "clang/EntoSA/PathSensitive/SVals.h"
-#include "clang/EntoSA/PathSensitive/SValBuilder.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
 
 using namespace clang;
 using namespace ento;
similarity index 99%
rename from lib/EntoSA/SVals.cpp
rename to lib/StaticAnalyzer/EntoSA/SVals.cpp
index ea23293924af599e2608799cf97ddedc4da159c8..dd8508a50b227562e8457f757dda4bd91591b95d 100644 (file)
@@ -12,7 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "clang/Basic/IdentifierTable.h"
 
 using namespace clang;
similarity index 98%
rename from lib/EntoSA/SimpleConstraintManager.cpp
rename to lib/StaticAnalyzer/EntoSA/SimpleConstraintManager.cpp
index ef26fc5d93750478155bb846ffbf85cf549c8161..e54d0ffe00d845bd01b7f158462a7f9f3cbbd2ce 100644 (file)
@@ -13,9 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "SimpleConstraintManager.h"
-#include "clang/EntoSA/PathSensitive/ExprEngine.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
-#include "clang/EntoSA/PathSensitive/Checker.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
 
 namespace clang {
 
similarity index 96%
rename from lib/EntoSA/SimpleConstraintManager.h
rename to lib/StaticAnalyzer/EntoSA/SimpleConstraintManager.h
index 83db8cc9cedaa83cd5d79632d985d15c60d477bd..75f67f7f17e5185df9be766716f1b7e1d7b72653 100644 (file)
@@ -14,8 +14,8 @@
 #ifndef LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
 #define LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
 
-#include "clang/EntoSA/PathSensitive/ConstraintManager.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 
 namespace clang {
 
similarity index 99%
rename from lib/EntoSA/SimpleSValBuilder.cpp
rename to lib/StaticAnalyzer/EntoSA/SimpleSValBuilder.cpp
index ac0bfa62ef77e391d840d23f66dbeb3b86fbe480..f1a9074b952dc5a29682c6a9758948bfd88c07ed 100644 (file)
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/SValBuilder.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 
 using namespace clang;
 using namespace ento;
similarity index 99%
rename from lib/EntoSA/Store.cpp
rename to lib/StaticAnalyzer/EntoSA/Store.cpp
index 29b0ee1b5fbeef74b67937f3d3f8b0998f0b6616..f1b83389ca63a5ecde30ddcf0bea2c5782297cdd 100644 (file)
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/Store.h"
-#include "clang/EntoSA/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
 #include "clang/AST/CharUnits.h"
 
 using namespace clang;
similarity index 98%
rename from lib/EntoSA/SymbolManager.cpp
rename to lib/StaticAnalyzer/EntoSA/SymbolManager.cpp
index 75e0774837f25aa5d4960a55fdaa31a8feef9871..08677dafcfa06c9ac1c1cfc278b8491236b9b37b 100644 (file)
@@ -12,9 +12,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
 #include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/EntoSA/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
similarity index 94%
rename from lib/EntoSA/TextPathDiagnostics.cpp
rename to lib/StaticAnalyzer/EntoSA/TextPathDiagnostics.cpp
index bf98301dc51399c8fc456ce5f869d6d16d623a6d..9ca378f2d410a0c28926f7fc71d28fe03c4bf518 100644 (file)
@@ -11,8 +11,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/EntoSA/PathDiagnosticClients.h"
-#include "clang/EntoSA/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
diff --git a/lib/StaticAnalyzer/Environment.cpp b/lib/StaticAnalyzer/Environment.cpp
new file mode 100644 (file)
index 0000000..1c74352
--- /dev/null
@@ -0,0 +1,236 @@
+//== Environment.cpp - Map from Stmt* to Locations/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 defined the Environment and EnvironmentManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+
+using namespace clang;
+using namespace ento;
+
+SVal Environment::lookupExpr(const Stmt* E) const {
+  const SVal* X = ExprBindings.lookup(E);
+  if (X) {
+    SVal V = *X;
+    return V;
+  }
+  return UnknownVal();
+}
+
+SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const {
+  for (;;) {
+    switch (E->getStmtClass()) {
+      case Stmt::AddrLabelExprClass:
+        return svalBuilder.makeLoc(cast<AddrLabelExpr>(E));
+      case Stmt::ParenExprClass:
+        // ParenExprs are no-ops.
+        E = cast<ParenExpr>(E)->getSubExpr();
+        continue;
+      case Stmt::CharacterLiteralClass: {
+        const CharacterLiteral* C = cast<CharacterLiteral>(E);
+        return svalBuilder.makeIntVal(C->getValue(), C->getType());
+      }
+      case Stmt::CXXBoolLiteralExprClass: {
+        const SVal *X = ExprBindings.lookup(E);
+        if (X) 
+          return *X;
+        else 
+          return svalBuilder.makeIntVal(cast<CXXBoolLiteralExpr>(E));
+      }
+      case Stmt::IntegerLiteralClass: {
+        // In C++, this expression may have been bound to a temporary object.
+        SVal const *X = ExprBindings.lookup(E);
+        if (X)
+          return *X;
+        else
+          return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
+      }
+      case Stmt::ImplicitCastExprClass:
+      case Stmt::CStyleCastExprClass: {
+        // We blast through no-op casts to get the descendant
+        // subexpression that has a value.
+        const CastExpr* C = cast<CastExpr>(E);
+        QualType CT = C->getType();
+        if (CT->isVoidType())
+          return UnknownVal();
+        if (C->getCastKind() == CK_NoOp) {
+          E = C->getSubExpr();
+          continue;
+        }
+        break;
+      }
+      case Stmt::ExprWithCleanupsClass:
+        E = cast<ExprWithCleanups>(E)->getSubExpr();
+        continue;
+      case Stmt::CXXBindTemporaryExprClass:
+        E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
+        continue;
+      case Stmt::CXXFunctionalCastExprClass:
+        E = cast<CXXFunctionalCastExpr>(E)->getSubExpr();
+        continue;        
+      // Handle all other Stmt* using a lookup.
+      default:
+        break;
+    };
+    break;
+  }
+  return lookupExpr(E);
+}
+
+Environment EnvironmentManager::bindExpr(Environment Env, const Stmt *S,
+                                         SVal V, bool Invalidate) {
+  assert(S);
+
+  if (V.isUnknown()) {
+    if (Invalidate)
+      return Environment(F.remove(Env.ExprBindings, S));
+    else
+      return Env;
+  }
+
+  return Environment(F.add(Env.ExprBindings, S, V));
+}
+
+static inline const Stmt *MakeLocation(const Stmt *S) {
+  return (const Stmt*) (((uintptr_t) S) | 0x1);
+}
+
+Environment EnvironmentManager::bindExprAndLocation(Environment Env,
+                                                    const Stmt *S,
+                                                    SVal location, SVal V) {
+  return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(S), location),
+                           S, V));
+}
+
+namespace {
+class MarkLiveCallback : public SymbolVisitor {
+  SymbolReaper &SymReaper;
+public:
+  MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
+  bool VisitSymbol(SymbolRef sym) { SymReaper.markLive(sym); return true; }
+};
+} // end anonymous namespace
+
+static bool isBlockExprInCallers(const Stmt *E, const LocationContext *LC) {
+  const LocationContext *ParentLC = LC->getParent();
+  while (ParentLC) {
+    CFG &C = *ParentLC->getCFG();
+    if (C.isBlkExpr(E))
+      return true;
+    ParentLC = ParentLC->getParent();
+  }
+
+  return false;
+}
+
+// In addition to mapping from Stmt * - > SVals in the Environment, we also
+// maintain a mapping from Stmt * -> SVals (locations) that were used during
+// a load and store.
+static inline bool IsLocation(const Stmt *S) {
+  return (bool) (((uintptr_t) S) & 0x1);
+}
+
+// RemoveDeadBindings:
+//  - Remove subexpression bindings.
+//  - Remove dead block expression bindings.
+//  - Keep live block expression bindings:
+//   - Mark their reachable symbols live in SymbolReaper,
+//     see ScanReachableSymbols.
+//   - Mark the region in DRoots if the binding is a loc::MemRegionVal.
+Environment
+EnvironmentManager::RemoveDeadBindings(Environment Env,
+                                       SymbolReaper &SymReaper,
+                                       const GRState *ST,
+                              llvm::SmallVectorImpl<const MemRegion*> &DRoots) {
+
+  CFG &C = *SymReaper.getLocationContext()->getCFG();
+
+  // We construct a new Environment object entirely, as this is cheaper than
+  // individually removing all the subexpression bindings (which will greatly
+  // outnumber block-level expression bindings).
+  Environment NewEnv = getInitialEnvironment();
+  
+  llvm::SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations;
+
+  // Iterate over the block-expr bindings.
+  for (Environment::iterator I = Env.begin(), E = Env.end();
+       I != E; ++I) {
+
+    const Stmt *BlkExpr = I.getKey();
+    
+    // For recorded locations (used when evaluating loads and stores), we
+    // consider them live only when their associated normal expression is
+    // also live.
+    // NOTE: This assumes that loads/stores that evaluated to UnknownVal
+    // still have an entry in the map.
+    if (IsLocation(BlkExpr)) {
+      deferredLocations.push_back(std::make_pair(BlkExpr, I.getData()));
+      continue;
+    }
+    
+    const SVal &X = I.getData();
+
+    // Block-level expressions in callers are assumed always live.
+    if (isBlockExprInCallers(BlkExpr, SymReaper.getLocationContext())) {
+      NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X);
+
+      if (isa<loc::MemRegionVal>(X)) {
+        const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion();
+        DRoots.push_back(R);
+      }
+
+      // Mark all symbols in the block expr's value live.
+      MarkLiveCallback cb(SymReaper);
+      ST->scanReachableSymbols(X, cb);
+      continue;
+    }
+
+    // Not a block-level expression?
+    if (!C.isBlkExpr(BlkExpr))
+      continue;
+
+    if (SymReaper.isLive(BlkExpr)) {
+      // Copy the binding to the new map.
+      NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X);
+
+      // If the block expr's value is a memory region, then mark that region.
+      if (isa<loc::MemRegionVal>(X)) {
+        const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion();
+        DRoots.push_back(R);
+      }
+
+      // Mark all symbols in the block expr's value live.
+      MarkLiveCallback cb(SymReaper);
+      ST->scanReachableSymbols(X, cb);
+      continue;
+    }
+
+    // Otherwise the expression is dead with a couple exceptions.
+    // Do not misclean LogicalExpr or ConditionalOperator.  It is dead at the
+    // beginning of itself, but we need its UndefinedVal to determine its
+    // SVal.
+    if (X.isUndef() && cast<UndefinedVal>(X).getData())
+      NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X);
+  }
+  
+  // Go through he deferred locations and add them to the new environment if
+  // the correspond Stmt* is in the map as well.
+  for (llvm::SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator
+      I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) {
+    const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1);
+    if (NewEnv.ExprBindings.lookup(S))
+      NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, I->first, I->second);
+  }
+
+  return NewEnv;
+}
diff --git a/lib/StaticAnalyzer/ExplodedGraph.cpp b/lib/StaticAnalyzer/ExplodedGraph.cpp
new file mode 100644 (file)
index 0000000..4c4612f
--- /dev/null
@@ -0,0 +1,282 @@
+//=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- 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 template classes ExplodedNode and ExplodedGraph,
+//  which represent a path-sensitive, intra-procedural "exploded graph."
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Node auditing.
+//===----------------------------------------------------------------------===//
+
+// An out of line virtual method to provide a home for the class vtable.
+ExplodedNode::Auditor::~Auditor() {}
+
+#ifndef NDEBUG
+static ExplodedNode::Auditor* NodeAuditor = 0;
+#endif
+
+void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
+#ifndef NDEBUG
+  NodeAuditor = A;
+#endif
+}
+
+//===----------------------------------------------------------------------===//
+// ExplodedNode.
+//===----------------------------------------------------------------------===//
+
+static inline BumpVector<ExplodedNode*>& getVector(void* P) {
+  return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P);
+}
+
+void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) {
+  assert (!V->isSink());
+  Preds.addNode(V, G);
+  V->Succs.addNode(this, G);
+#ifndef NDEBUG
+  if (NodeAuditor) NodeAuditor->AddEdge(V, this);
+#endif
+}
+
+void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) {
+  assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
+  assert(!getFlag());
+
+  if (getKind() == Size1) {
+    if (ExplodedNode* NOld = getNode()) {
+      BumpVectorContext &Ctx = G.getNodeAllocator();
+      BumpVector<ExplodedNode*> *V = 
+        G.getAllocator().Allocate<BumpVector<ExplodedNode*> >();
+      new (V) BumpVector<ExplodedNode*>(Ctx, 4);
+      
+      assert((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
+      V->push_back(NOld, Ctx);
+      V->push_back(N, Ctx);
+      P = reinterpret_cast<uintptr_t>(V) | SizeOther;
+      assert(getPtr() == (void*) V);
+      assert(getKind() == SizeOther);
+    }
+    else {
+      P = reinterpret_cast<uintptr_t>(N);
+      assert(getKind() == Size1);
+    }
+  }
+  else {
+    assert(getKind() == SizeOther);
+    getVector(getPtr()).push_back(N, G.getNodeAllocator());
+  }
+}
+
+unsigned ExplodedNode::NodeGroup::size() const {
+  if (getFlag())
+    return 0;
+
+  if (getKind() == Size1)
+    return getNode() ? 1 : 0;
+  else
+    return getVector(getPtr()).size();
+}
+
+ExplodedNode **ExplodedNode::NodeGroup::begin() const {
+  if (getFlag())
+    return NULL;
+
+  if (getKind() == Size1)
+    return (ExplodedNode**) (getPtr() ? &P : NULL);
+  else
+    return const_cast<ExplodedNode**>(&*(getVector(getPtr()).begin()));
+}
+
+ExplodedNode** ExplodedNode::NodeGroup::end() const {
+  if (getFlag())
+    return NULL;
+
+  if (getKind() == Size1)
+    return (ExplodedNode**) (getPtr() ? &P+1 : NULL);
+  else {
+    // Dereferencing end() is undefined behaviour. The vector is not empty, so
+    // we can dereference the last elem and then add 1 to the result.
+    return const_cast<ExplodedNode**>(getVector(getPtr()).end());
+  }
+}
+
+ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L,
+                                     const GRState* State, bool* IsNew) {
+  // Profile 'State' to determine if we already have an existing node.
+  llvm::FoldingSetNodeID profile;
+  void* InsertPos = 0;
+
+  NodeTy::Profile(profile, L, State);
+  NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
+
+  if (!V) {
+    // Allocate a new node.
+    V = (NodeTy*) getAllocator().Allocate<NodeTy>();
+    new (V) NodeTy(L, State);
+
+    // Insert the node into the node set and return it.
+    Nodes.InsertNode(V, InsertPos);
+
+    ++NumNodes;
+
+    if (IsNew) *IsNew = true;
+  }
+  else
+    if (IsNew) *IsNew = false;
+
+  return V;
+}
+
+std::pair<ExplodedGraph*, InterExplodedGraphMap*>
+ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
+               llvm::DenseMap<const void*, const void*> *InverseMap) const {
+
+  if (NBeg == NEnd)
+    return std::make_pair((ExplodedGraph*) 0,
+                          (InterExplodedGraphMap*) 0);
+
+  assert (NBeg < NEnd);
+
+  llvm::OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
+
+  ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
+
+  return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
+}
+
+ExplodedGraph*
+ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
+                            const ExplodedNode* const* EndSources,
+                            InterExplodedGraphMap* M,
+                   llvm::DenseMap<const void*, const void*> *InverseMap) const {
+
+  typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
+  Pass1Ty Pass1;
+
+  typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
+  Pass2Ty& Pass2 = M->M;
+
+  llvm::SmallVector<const ExplodedNode*, 10> WL1, WL2;
+
+  // ===- Pass 1 (reverse DFS) -===
+  for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
+    assert(*I);
+    WL1.push_back(*I);
+  }
+
+  // Process the first worklist until it is empty.  Because it is a std::list
+  // it acts like a FIFO queue.
+  while (!WL1.empty()) {
+    const ExplodedNode *N = WL1.back();
+    WL1.pop_back();
+
+    // Have we already visited this node?  If so, continue to the next one.
+    if (Pass1.count(N))
+      continue;
+
+    // Otherwise, mark this node as visited.
+    Pass1.insert(N);
+
+    // If this is a root enqueue it to the second worklist.
+    if (N->Preds.empty()) {
+      WL2.push_back(N);
+      continue;
+    }
+
+    // Visit our predecessors and enqueue them.
+    for (ExplodedNode** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I)
+      WL1.push_back(*I);
+  }
+
+  // We didn't hit a root? Return with a null pointer for the new graph.
+  if (WL2.empty())
+    return 0;
+
+  // Create an empty graph.
+  ExplodedGraph* G = MakeEmptyGraph();
+
+  // ===- Pass 2 (forward DFS to construct the new graph) -===
+  while (!WL2.empty()) {
+    const ExplodedNode* N = WL2.back();
+    WL2.pop_back();
+
+    // Skip this node if we have already processed it.
+    if (Pass2.find(N) != Pass2.end())
+      continue;
+
+    // Create the corresponding node in the new graph and record the mapping
+    // from the old node to the new node.
+    ExplodedNode* NewN = G->getNode(N->getLocation(), N->State, NULL);
+    Pass2[N] = NewN;
+
+    // Also record the reverse mapping from the new node to the old node.
+    if (InverseMap) (*InverseMap)[NewN] = N;
+
+    // If this node is a root, designate it as such in the graph.
+    if (N->Preds.empty())
+      G->addRoot(NewN);
+
+    // In the case that some of the intended predecessors of NewN have already
+    // been created, we should hook them up as predecessors.
+
+    // Walk through the predecessors of 'N' and hook up their corresponding
+    // nodes in the new graph (if any) to the freshly created node.
+    for (ExplodedNode **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
+      Pass2Ty::iterator PI = Pass2.find(*I);
+      if (PI == Pass2.end())
+        continue;
+
+      NewN->addPredecessor(PI->second, *G);
+    }
+
+    // In the case that some of the intended successors of NewN have already
+    // been created, we should hook them up as successors.  Otherwise, enqueue
+    // the new nodes from the original graph that should have nodes created
+    // in the new graph.
+    for (ExplodedNode **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
+      Pass2Ty::iterator PI = Pass2.find(*I);
+      if (PI != Pass2.end()) {
+        PI->second->addPredecessor(NewN, *G);
+        continue;
+      }
+
+      // Enqueue nodes to the worklist that were marked during pass 1.
+      if (Pass1.count(*I))
+        WL2.push_back(*I);
+    }
+
+    // Finally, explictly mark all nodes without any successors as sinks.
+    if (N->isSink())
+      NewN->markAsSink();
+  }
+
+  return G;
+}
+
+ExplodedNode*
+InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const {
+  llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
+    M.find(N);
+
+  return I == M.end() ? 0 : I->second;
+}
+
diff --git a/lib/StaticAnalyzer/FlatStore.cpp b/lib/StaticAnalyzer/FlatStore.cpp
new file mode 100644 (file)
index 0000000..1558db7
--- /dev/null
@@ -0,0 +1,203 @@
+//=== FlatStore.cpp - Flat region-based store model -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "llvm/ADT/ImmutableIntervalMap.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::Interval;
+
+// The actual store type.
+typedef llvm::ImmutableIntervalMap<SVal> BindingVal;
+typedef llvm::ImmutableMap<const MemRegion *, BindingVal> RegionBindings;
+
+namespace {
+class FlatStoreManager : public StoreManager {
+  RegionBindings::Factory RBFactory;
+  BindingVal::Factory BVFactory;
+
+public:
+  FlatStoreManager(GRStateManager &mgr) 
+    : StoreManager(mgr), 
+      RBFactory(mgr.getAllocator()), 
+      BVFactory(mgr.getAllocator()) {}
+
+  SVal Retrieve(Store store, Loc L, QualType T);
+  Store Bind(Store store, Loc L, SVal val);
+  Store Remove(Store St, Loc L);
+  Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* cl,
+                            const LocationContext *LC, SVal v);
+
+  Store getInitialStore(const LocationContext *InitLoc) {
+    return RBFactory.getEmptyMap().getRoot();
+  }
+
+  SubRegionMap *getSubRegionMap(Store store) {
+    return 0;
+  }
+
+  SVal ArrayToPointer(Loc Array);
+  Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx,
+                           SymbolReaper& SymReaper,
+                         llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){
+    return store;
+  }
+
+  Store BindDecl(Store store, const VarRegion *VR, SVal initVal);
+
+  Store BindDeclWithNoInit(Store store, const VarRegion *VR);
+
+  typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+  
+  Store InvalidateRegions(Store store, const MemRegion * const *I,
+                          const MemRegion * const *E, const Expr *Ex,
+                          unsigned Count, InvalidatedSymbols *IS,
+                          bool invalidateGlobals, InvalidatedRegions *Regions);
+
+  void print(Store store, llvm::raw_ostream& Out, const char* nl, 
+             const char *sep);
+  void iterBindings(Store store, BindingsHandler& f);
+
+private:
+  static RegionBindings getRegionBindings(Store store) {
+    return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+  }
+
+  class RegionInterval {
+  public:
+    const MemRegion *R;
+    Interval I;
+    RegionInterval(const MemRegion *r, int64_t s, int64_t e) : R(r), I(s, e){}
+  };
+
+  RegionInterval RegionToInterval(const MemRegion *R);
+
+  SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T);
+};
+} // end anonymous namespace
+
+StoreManager *ento::CreateFlatStoreManager(GRStateManager &StMgr) {
+  return new FlatStoreManager(StMgr);
+}
+
+SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) {
+  const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+  RegionInterval RI = RegionToInterval(R);
+  // FIXME: FlatStore should handle regions with unknown intervals.
+  if (!RI.R)
+    return UnknownVal();
+
+  RegionBindings B = getRegionBindings(store);
+  const BindingVal *BV = B.lookup(RI.R);
+  if (BV) {
+    const SVal *V = BVFactory.lookup(*BV, RI.I);
+    if (V)
+      return *V;
+    else
+      return RetrieveRegionWithNoBinding(R, T);
+  }
+  return RetrieveRegionWithNoBinding(R, T);
+}
+
+SVal FlatStoreManager::RetrieveRegionWithNoBinding(const MemRegion *R,
+                                                   QualType T) {
+  if (R->hasStackNonParametersStorage())
+    return UndefinedVal();
+  else
+    return svalBuilder.getRegionValueSymbolVal(cast<TypedRegion>(R));
+}
+
+Store FlatStoreManager::Bind(Store store, Loc L, SVal val) {
+  const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+  RegionBindings B = getRegionBindings(store);
+  const BindingVal *V = B.lookup(R);
+
+  BindingVal BV = BVFactory.getEmptyMap();
+  if (V)
+    BV = *V;
+
+  RegionInterval RI = RegionToInterval(R);
+  // FIXME: FlatStore should handle regions with unknown intervals.
+  if (!RI.R)
+    return B.getRoot();
+  BV = BVFactory.add(BV, RI.I, val);
+  B = RBFactory.add(B, RI.R, BV);
+  return B.getRoot();
+}
+
+Store FlatStoreManager::Remove(Store store, Loc L) {
+  return store;
+}
+
+Store FlatStoreManager::BindCompoundLiteral(Store store,
+                                            const CompoundLiteralExpr* cl,
+                                            const LocationContext *LC,
+                                            SVal v) {
+  return store;
+}
+
+SVal FlatStoreManager::ArrayToPointer(Loc Array) {
+  return Array;
+}
+
+Store FlatStoreManager::BindDecl(Store store, const VarRegion *VR, 
+                                 SVal initVal) {
+  return Bind(store, svalBuilder.makeLoc(VR), initVal);
+}
+
+Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) {
+  return store;
+}
+
+Store FlatStoreManager::InvalidateRegions(Store store,
+                                          const MemRegion * const *I,
+                                          const MemRegion * const *E,
+                                          const Expr *Ex, unsigned Count,
+                                          InvalidatedSymbols *IS,
+                                          bool invalidateGlobals,
+                                          InvalidatedRegions *Regions) {
+  assert(false && "Not implemented");
+  return store;
+}
+
+void FlatStoreManager::print(Store store, llvm::raw_ostream& Out, 
+                             const char* nl, const char *sep) {
+}
+
+void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) {
+}
+
+FlatStoreManager::RegionInterval 
+FlatStoreManager::RegionToInterval(const MemRegion *R) { 
+  switch (R->getKind()) {
+  case MemRegion::VarRegionKind: {
+    QualType T = cast<VarRegion>(R)->getValueType();
+    int64_t Size = Ctx.getTypeSize(T);
+    return RegionInterval(R, 0, Size-1);
+  }
+
+  case MemRegion::ElementRegionKind: 
+  case MemRegion::FieldRegionKind: {
+    RegionOffset Offset = R->getAsOffset();
+    // We cannot compute offset for all regions, for example, elements
+    // with symbolic offsets.
+    if (!Offset.getRegion())
+      return RegionInterval(0, 0, 0);
+    int64_t Start = Offset.getOffset();
+    int64_t Size = Ctx.getTypeSize(cast<TypedRegion>(R)->getValueType());
+    return RegionInterval(Offset.getRegion(), Start, Start+Size);
+  }
+
+  default:
+    llvm_unreachable("Region kind unhandled.");
+    return RegionInterval(0, 0, 0);
+  }
+}
diff --git a/lib/StaticAnalyzer/GRState.cpp b/lib/StaticAnalyzer/GRState.cpp
new file mode 100644 (file)
index 0000000..12c8968
--- /dev/null
@@ -0,0 +1,551 @@
+//= GRState.cpp - Path-Sensitive "State" for tracking 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 implements GRState and GRStateManager.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+// Give the vtable for ConstraintManager somewhere to live.
+// FIXME: Move this elsewhere.
+ConstraintManager::~ConstraintManager() {}
+
+GRStateManager::~GRStateManager() {
+  for (std::vector<GRState::Printer*>::iterator I=Printers.begin(),
+        E=Printers.end(); I!=E; ++I)
+    delete *I;
+
+  for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();
+       I!=E; ++I)
+    I->second.second(I->second.first);
+}
+
+const GRState*
+GRStateManager::RemoveDeadBindings(const GRState* state,
+                                   const StackFrameContext *LCtx,
+                                   SymbolReaper& SymReaper) {
+
+  // This code essentially performs a "mark-and-sweep" of the VariableBindings.
+  // The roots are any Block-level exprs and Decls that our liveness algorithm
+  // tells us are live.  We then see what Decls they may reference, and keep
+  // those around.  This code more than likely can be made faster, and the
+  // frequency of which this method is called should be experimented with
+  // for optimum performance.
+  llvm::SmallVector<const MemRegion*, 10> RegionRoots;
+  GRState NewState = *state;
+
+  NewState.Env = EnvMgr.RemoveDeadBindings(NewState.Env, SymReaper,
+                                           state, RegionRoots);
+
+  // Clean up the store.
+  NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, LCtx, 
+                                             SymReaper, RegionRoots);
+  state = getPersistentState(NewState);
+  return ConstraintMgr->RemoveDeadBindings(state, SymReaper);
+}
+
+const GRState *GRStateManager::MarshalState(const GRState *state,
+                                            const StackFrameContext *InitLoc) {
+  // make up an empty state for now.
+  GRState State(this,
+                EnvMgr.getInitialEnvironment(),
+                StoreMgr->getInitialStore(InitLoc),
+                GDMFactory.getEmptyMap());
+
+  return getPersistentState(State);
+}
+
+const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
+                                            const LocationContext *LC,
+                                            SVal V) const {
+  Store new_store = 
+    getStateManager().StoreMgr->BindCompoundLiteral(St, CL, LC, V);
+  return makeWithStore(new_store);
+}
+
+const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const {
+  Store new_store = getStateManager().StoreMgr->BindDecl(St, VR, IVal);
+  return makeWithStore(new_store);
+}
+
+const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const {
+  Store new_store = getStateManager().StoreMgr->BindDeclWithNoInit(St, VR);
+  return makeWithStore(new_store);
+}
+
+const GRState *GRState::bindLoc(Loc LV, SVal V) const {
+  GRStateManager &Mgr = getStateManager();
+  Store new_store = Mgr.StoreMgr->Bind(St, LV, V);
+  const GRState *new_state = makeWithStore(new_store);
+
+  const MemRegion *MR = LV.getAsRegion();
+  if (MR)
+    return Mgr.getOwningEngine().ProcessRegionChange(new_state, MR);
+
+  return new_state;
+}
+
+const GRState *GRState::bindDefault(SVal loc, SVal V) const {
+  GRStateManager &Mgr = getStateManager();
+  const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion();
+  Store new_store = Mgr.StoreMgr->BindDefault(St, R, V);
+  const GRState *new_state = makeWithStore(new_store);
+  return Mgr.getOwningEngine().ProcessRegionChange(new_state, R);
+}
+
+const GRState *GRState::InvalidateRegions(const MemRegion * const *Begin,
+                                          const MemRegion * const *End,
+                                          const Expr *E, unsigned Count,
+                                          StoreManager::InvalidatedSymbols *IS,
+                                          bool invalidateGlobals) const {
+  GRStateManager &Mgr = getStateManager();
+  SubEngine &Eng = Mgr.getOwningEngine();
+
+  if (Eng.WantsRegionChangeUpdate(this)) {
+    StoreManager::InvalidatedRegions Regions;
+
+    Store new_store = Mgr.StoreMgr->InvalidateRegions(St, Begin, End,
+                                                      E, Count, IS,
+                                                      invalidateGlobals,
+                                                      &Regions);
+    const GRState *new_state = makeWithStore(new_store);
+
+    return Eng.ProcessRegionChanges(new_state,
+                                    &Regions.front(),
+                                    &Regions.back()+1);
+  }
+
+  Store new_store = Mgr.StoreMgr->InvalidateRegions(St, Begin, End,
+                                                    E, Count, IS,
+                                                    invalidateGlobals,
+                                                    NULL);
+  return makeWithStore(new_store);
+}
+
+const GRState *GRState::unbindLoc(Loc LV) const {
+  assert(!isa<loc::MemRegionVal>(LV) && "Use InvalidateRegion instead.");
+
+  Store OldStore = getStore();
+  Store NewStore = getStateManager().StoreMgr->Remove(OldStore, LV);
+
+  if (NewStore == OldStore)
+    return this;
+
+  return makeWithStore(NewStore);
+}
+
+const GRState *GRState::EnterStackFrame(const StackFrameContext *frame) const {
+  Store new_store = getStateManager().StoreMgr->EnterStackFrame(this, frame);
+  return makeWithStore(new_store);
+}
+
+SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const {
+  // We only want to do fetches from regions that we can actually bind
+  // values.  For example, SymbolicRegions of type 'id<...>' cannot
+  // have direct bindings (but their can be bindings on their subregions).
+  if (!R->isBoundable())
+    return UnknownVal();
+
+  if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+    QualType T = TR->getValueType();
+    if (Loc::IsLocType(T) || T->isIntegerType())
+      return getSVal(R);
+  }
+
+  return UnknownVal();
+}
+
+SVal GRState::getSVal(Loc location, QualType T) const {
+  SVal V = getRawSVal(cast<Loc>(location), T);
+
+  // If 'V' is a symbolic value that is *perfectly* constrained to
+  // be a constant value, use that value instead to lessen the burden
+  // on later analysis stages (so we have less symbolic values to reason
+  // about).
+  if (!T.isNull()) {
+    if (SymbolRef sym = V.getAsSymbol()) {
+      if (const llvm::APSInt *Int = getSymVal(sym)) {
+        // FIXME: Because we don't correctly model (yet) sign-extension
+        // and truncation of symbolic values, we need to convert
+        // the integer value to the correct signedness and bitwidth.
+        //
+        // This shows up in the following:
+        //
+        //   char foo();
+        //   unsigned x = foo();
+        //   if (x == 54)
+        //     ...
+        //
+        //  The symbolic value stored to 'x' is actually the conjured
+        //  symbol for the call to foo(); the type of that symbol is 'char',
+        //  not unsigned.
+        const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int);
+        
+        if (isa<Loc>(V))
+          return loc::ConcreteInt(NewV);
+        else
+          return nonloc::ConcreteInt(NewV);
+      }
+    }
+  }
+  
+  return V;
+}
+
+const GRState *GRState::BindExpr(const Stmt* S, SVal V, bool Invalidate) const{
+  Environment NewEnv = getStateManager().EnvMgr.bindExpr(Env, S, V,
+                                                         Invalidate);
+  if (NewEnv == Env)
+    return this;
+
+  GRState NewSt = *this;
+  NewSt.Env = NewEnv;
+  return getStateManager().getPersistentState(NewSt);
+}
+
+const GRState *GRState::bindExprAndLocation(const Stmt *S, SVal location,
+                                            SVal V) const {
+  Environment NewEnv =
+    getStateManager().EnvMgr.bindExprAndLocation(Env, S, location, V);
+
+  if (NewEnv == Env)
+    return this;
+  
+  GRState NewSt = *this;
+  NewSt.Env = NewEnv;
+  return getStateManager().getPersistentState(NewSt);
+}
+
+const GRState *GRState::assumeInBound(DefinedOrUnknownSVal Idx,
+                                      DefinedOrUnknownSVal UpperBound,
+                                      bool Assumption) const {
+  if (Idx.isUnknown() || UpperBound.isUnknown())
+    return this;
+
+  // Build an expression for 0 <= Idx < UpperBound.
+  // This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed.
+  // FIXME: This should probably be part of SValBuilder.
+  GRStateManager &SM = getStateManager();
+  SValBuilder &svalBuilder = SM.getSValBuilder();
+  ASTContext &Ctx = svalBuilder.getContext();
+
+  // Get the offset: the minimum value of the array index type.
+  BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
+  // FIXME: This should be using ValueManager::ArrayindexTy...somehow.
+  QualType indexTy = Ctx.IntTy;
+  nonloc::ConcreteInt Min(BVF.getMinValue(indexTy));
+
+  // Adjust the index.
+  SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add,
+                                        cast<NonLoc>(Idx), Min, indexTy);
+  if (newIdx.isUnknownOrUndef())
+    return this;
+
+  // Adjust the upper bound.
+  SVal newBound =
+    svalBuilder.evalBinOpNN(this, BO_Add, cast<NonLoc>(UpperBound),
+                            Min, indexTy);
+
+  if (newBound.isUnknownOrUndef())
+    return this;
+
+  // Build the actual comparison.
+  SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT,
+                                cast<NonLoc>(newIdx), cast<NonLoc>(newBound),
+                                Ctx.IntTy);
+  if (inBound.isUnknownOrUndef())
+    return this;
+
+  // Finally, let the constraint manager take care of it.
+  ConstraintManager &CM = SM.getConstraintManager();
+  return CM.assume(this, cast<DefinedSVal>(inBound), Assumption);
+}
+
+const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) {
+  GRState State(this,
+                EnvMgr.getInitialEnvironment(),
+                StoreMgr->getInitialStore(InitLoc),
+                GDMFactory.getEmptyMap());
+
+  return getPersistentState(State);
+}
+
+const GRState* GRStateManager::getPersistentState(GRState& State) {
+
+  llvm::FoldingSetNodeID ID;
+  State.Profile(ID);
+  void* InsertPos;
+
+  if (GRState* I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
+    return I;
+
+  GRState* I = (GRState*) Alloc.Allocate<GRState>();
+  new (I) GRState(State);
+  StateSet.InsertNode(I, InsertPos);
+  return I;
+}
+
+const GRState* GRState::makeWithStore(Store store) const {
+  GRState NewSt = *this;
+  NewSt.St = store;
+  return getStateManager().getPersistentState(NewSt);
+}
+
+//===----------------------------------------------------------------------===//
+//  State pretty-printing.
+//===----------------------------------------------------------------------===//
+
+static bool IsEnvLoc(const Stmt *S) {
+  // FIXME: This is a layering violation.  Should be in environment.
+  return (bool) (((uintptr_t) S) & 0x1);
+}
+
+void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl,
+                    const char* sep) const {
+  // Print the store.
+  GRStateManager &Mgr = getStateManager();
+  Mgr.getStoreManager().print(getStore(), Out, nl, sep);
+
+  // Print Subexpression bindings.
+  bool isFirst = true;
+
+  // FIXME: All environment printing should be moved inside Environment.
+  for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
+    if (C.isBlkExpr(I.getKey()) || IsEnvLoc(I.getKey()))
+      continue;
+
+    if (isFirst) {
+      Out << nl << nl << "Sub-Expressions:" << nl;
+      isFirst = false;
+    }
+    else { Out << nl; }
+
+    Out << " (" << (void*) I.getKey() << ") ";
+    LangOptions LO; // FIXME.
+    I.getKey()->printPretty(Out, 0, PrintingPolicy(LO));
+    Out << " : " << I.getData();
+  }
+
+  // Print block-expression bindings.
+  isFirst = true;
+
+  for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
+    if (!C.isBlkExpr(I.getKey()))
+      continue;
+
+    if (isFirst) {
+      Out << nl << nl << "Block-level Expressions:" << nl;
+      isFirst = false;
+    }
+    else { Out << nl; }
+
+    Out << " (" << (void*) I.getKey() << ") ";
+    LangOptions LO; // FIXME.
+    I.getKey()->printPretty(Out, 0, PrintingPolicy(LO));
+    Out << " : " << I.getData();
+  }
+  
+  // Print locations.
+  isFirst = true;
+  
+  for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
+    if (!IsEnvLoc(I.getKey()))
+      continue;
+    
+    if (isFirst) {
+      Out << nl << nl << "Load/store locations:" << nl;
+      isFirst = false;
+    }
+    else { Out << nl; }
+
+    const Stmt *S = (Stmt*) (((uintptr_t) I.getKey()) & ((uintptr_t) ~0x1));
+    
+    Out << " (" << (void*) S << ") ";
+    LangOptions LO; // FIXME.
+    S->printPretty(Out, 0, PrintingPolicy(LO));
+    Out << " : " << I.getData();
+  }
+
+  Mgr.getConstraintManager().print(this, Out, nl, sep);
+
+  // Print checker-specific data.
+  for (std::vector<Printer*>::iterator I = Mgr.Printers.begin(),
+                                       E = Mgr.Printers.end(); I != E; ++I) {
+    (*I)->Print(Out, this, nl, sep);
+  }
+}
+
+void GRState::printDOT(llvm::raw_ostream& Out, CFG &C) const {
+  print(Out, C, "\\l", "\\|");
+}
+
+void GRState::printStdErr(CFG &C) const {
+  print(llvm::errs(), C);
+}
+
+//===----------------------------------------------------------------------===//
+// Generic Data Map.
+//===----------------------------------------------------------------------===//
+
+void* const* GRState::FindGDM(void* K) const {
+  return GDM.lookup(K);
+}
+
+void*
+GRStateManager::FindGDMContext(void* K,
+                               void* (*CreateContext)(llvm::BumpPtrAllocator&),
+                               void (*DeleteContext)(void*)) {
+
+  std::pair<void*, void (*)(void*)>& p = GDMContexts[K];
+  if (!p.first) {
+    p.first = CreateContext(Alloc);
+    p.second = DeleteContext;
+  }
+
+  return p.first;
+}
+
+const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
+  GRState::GenericDataMap M1 = St->getGDM();
+  GRState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);
+
+  if (M1 == M2)
+    return St;
+
+  GRState NewSt = *St;
+  NewSt.GDM = M2;
+  return getPersistentState(NewSt);
+}
+
+const GRState *GRStateManager::removeGDM(const GRState *state, void *Key) {
+  GRState::GenericDataMap OldM = state->getGDM();
+  GRState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);
+
+  if (NewM == OldM)
+    return state;
+
+  GRState NewState = *state;
+  NewState.GDM = NewM;
+  return getPersistentState(NewState);
+}
+
+//===----------------------------------------------------------------------===//
+// Utility.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ScanReachableSymbols : public SubRegionMap::Visitor  {
+  typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy;
+
+  VisitedRegionsTy visited;
+  const GRState *state;
+  SymbolVisitor &visitor;
+  llvm::OwningPtr<SubRegionMap> SRM;
+public:
+
+  ScanReachableSymbols(const GRState *st, SymbolVisitor& v)
+    : state(st), visitor(v) {}
+
+  bool scan(nonloc::CompoundVal val);
+  bool scan(SVal val);
+  bool scan(const MemRegion *R);
+
+  // From SubRegionMap::Visitor.
+  bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) {
+    return scan(SubRegion);
+  }
+};
+}
+
+bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
+  for (nonloc::CompoundVal::iterator I=val.begin(), E=val.end(); I!=E; ++I)
+    if (!scan(*I))
+      return false;
+
+  return true;
+}
+
+bool ScanReachableSymbols::scan(SVal val) {
+  if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
+    return scan(X->getRegion());
+
+  if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
+    return scan(X->getLoc());
+
+  if (SymbolRef Sym = val.getAsSymbol())
+    return visitor.VisitSymbol(Sym);
+
+  if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val))
+    return scan(*X);
+
+  return true;
+}
+
+bool ScanReachableSymbols::scan(const MemRegion *R) {
+  if (isa<MemSpaceRegion>(R) || visited.count(R))
+    return true;
+
+  visited.insert(R);
+
+  // If this is a symbolic region, visit the symbol for the region.
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+    if (!visitor.VisitSymbol(SR->getSymbol()))
+      return false;
+
+  // If this is a subregion, also visit the parent regions.
+  if (const SubRegion *SR = dyn_cast<SubRegion>(R))
+    if (!scan(SR->getSuperRegion()))
+      return false;
+
+  // Now look at the binding to this region (if any).
+  if (!scan(state->getSValAsScalarOrLoc(R)))
+    return false;
+
+  // Now look at the subregions.
+  if (!SRM.get())
+    SRM.reset(state->getStateManager().getStoreManager().
+                                           getSubRegionMap(state->getStore()));
+
+  return SRM->iterSubRegions(R, *this);
+}
+
+bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
+  ScanReachableSymbols S(this, visitor);
+  return S.scan(val);
+}
+
+bool GRState::scanReachableSymbols(const SVal *I, const SVal *E,
+                                   SymbolVisitor &visitor) const {
+  ScanReachableSymbols S(this, visitor);
+  for ( ; I != E; ++I) {
+    if (!S.scan(*I))
+      return false;
+  }
+  return true;
+}
+
+bool GRState::scanReachableSymbols(const MemRegion * const *I,
+                                   const MemRegion * const *E,
+                                   SymbolVisitor &visitor) const {
+  ScanReachableSymbols S(this, visitor);
+  for ( ; I != E; ++I) {
+    if (!S.scan(*I))
+      return false;
+  }
+  return true;
+}
diff --git a/lib/StaticAnalyzer/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/HTMLDiagnostics.cpp
new file mode 100644 (file)
index 0000000..659c32d
--- /dev/null
@@ -0,0 +1,578 @@
+//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- 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 HTMLDiagnostics object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Boilerplate.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class HTMLDiagnostics : public PathDiagnosticClient {
+  llvm::sys::Path Directory, FilePrefix;
+  bool createdDir, noDir;
+  const Preprocessor &PP;
+  std::vector<const PathDiagnostic*> BatchedDiags;
+public:
+  HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
+
+  virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
+
+  virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade);
+
+  virtual void HandlePathDiagnostic(const PathDiagnostic* D);
+
+  virtual llvm::StringRef getName() const {
+    return "HTMLDiagnostics";
+  }
+
+  unsigned ProcessMacroPiece(llvm::raw_ostream& os,
+                             const PathDiagnosticMacroPiece& P,
+                             unsigned num);
+
+  void HandlePiece(Rewriter& R, FileID BugFileID,
+                   const PathDiagnosticPiece& P, unsigned num, unsigned max);
+
+  void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range,
+                      const char *HighlightStart = "<span class=\"mrange\">",
+                      const char *HighlightEnd = "</span>");
+
+  void ReportDiag(const PathDiagnostic& D,
+                  llvm::SmallVectorImpl<std::string> *FilesMade);
+};
+
+} // end anonymous namespace
+
+HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
+                                 const Preprocessor &pp)
+  : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
+    PP(pp) {
+  // All html files begin with "report"
+  FilePrefix.appendComponent("report");
+}
+
+PathDiagnosticClient*
+ento::createHTMLDiagnosticClient(const std::string& prefix,
+                                 const Preprocessor &PP) {
+  return new HTMLDiagnostics(prefix, PP);
+}
+
+//===----------------------------------------------------------------------===//
+// Report processing.
+//===----------------------------------------------------------------------===//
+
+void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+  if (!D)
+    return;
+
+  if (D->empty()) {
+    delete D;
+    return;
+  }
+
+  const_cast<PathDiagnostic*>(D)->flattenLocations();
+  BatchedDiags.push_back(D);
+}
+
+void
+HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade)
+{
+  while (!BatchedDiags.empty()) {
+    const PathDiagnostic* D = BatchedDiags.back();
+    BatchedDiags.pop_back();
+    ReportDiag(*D, FilesMade);
+    delete D;
+  }
+
+  BatchedDiags.clear();
+}
+
+void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
+                                 llvm::SmallVectorImpl<std::string> *FilesMade){
+  // Create the HTML directory if it is missing.
+  if (!createdDir) {
+    createdDir = true;
+    std::string ErrorMsg;
+    Directory.createDirectoryOnDisk(true, &ErrorMsg);
+
+    if (!Directory.isDirectory()) {
+      llvm::errs() << "warning: could not create directory '"
+                   << Directory.str() << "'\n"
+                   << "reason: " << ErrorMsg << '\n';
+
+      noDir = true;
+
+      return;
+    }
+  }
+
+  if (noDir)
+    return;
+
+  const SourceManager &SMgr = D.begin()->getLocation().getManager();
+  FileID FID;
+
+  // Verify that the entire path is from the same FileID.
+  for (PathDiagnostic::const_iterator I = D.begin(), E = D.end(); I != E; ++I) {
+    FullSourceLoc L = I->getLocation().asLocation().getInstantiationLoc();
+
+    if (FID.isInvalid()) {
+      FID = SMgr.getFileID(L);
+    } else if (SMgr.getFileID(L) != FID)
+      return; // FIXME: Emit a warning?
+
+    // Check the source ranges.
+    for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
+                                             RE=I->ranges_end(); RI!=RE; ++RI) {
+
+      SourceLocation L = SMgr.getInstantiationLoc(RI->getBegin());
+
+      if (!L.isFileID() || SMgr.getFileID(L) != FID)
+        return; // FIXME: Emit a warning?
+
+      L = SMgr.getInstantiationLoc(RI->getEnd());
+
+      if (!L.isFileID() || SMgr.getFileID(L) != FID)
+        return; // FIXME: Emit a warning?
+    }
+  }
+
+  if (FID.isInvalid())
+    return; // FIXME: Emit a warning?
+
+  // Create a new rewriter to generate HTML.
+  Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOptions());
+
+  // Process the path.
+  unsigned n = D.size();
+  unsigned max = n;
+
+  for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
+        I!=E; ++I, --n)
+    HandlePiece(R, FID, *I, n, max);
+
+  // Add line numbers, header, footer, etc.
+
+  // unsigned FID = R.getSourceMgr().getMainFileID();
+  html::EscapeText(R, FID);
+  html::AddLineNumbers(R, FID);
+
+  // If we have a preprocessor, relex the file and syntax highlight.
+  // We might not have a preprocessor if we come from a deserialized AST file,
+  // for example.
+
+  html::SyntaxHighlight(R, FID, PP);
+  html::HighlightMacros(R, FID, PP);
+
+  // Get the full directory name of the analyzed file.
+
+  const FileEntry* Entry = SMgr.getFileEntryForID(FID);
+
+  // This is a cludge; basically we want to append either the full
+  // working directory if we have no directory information.  This is
+  // a work in progress.
+
+  std::string DirName = "";
+
+  if (llvm::sys::path::is_relative(Entry->getName())) {
+    llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+    DirName = P.str() + "/";
+  }
+
+  // Add the name of the file as an <h1> tag.
+
+  {
+    std::string s;
+    llvm::raw_string_ostream os(s);
+
+    os << "<!-- REPORTHEADER -->\n"
+      << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
+          "<tr><td class=\"rowname\">File:</td><td>"
+      << html::EscapeText(DirName)
+      << html::EscapeText(Entry->getName())
+      << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
+         "<a href=\"#EndPath\">line "
+      << (*D.rbegin()).getLocation().asLocation().getInstantiationLineNumber()
+      << ", column "
+      << (*D.rbegin()).getLocation().asLocation().getInstantiationColumnNumber()
+      << "</a></td></tr>\n"
+         "<tr><td class=\"rowname\">Description:</td><td>"
+      << D.getDescription() << "</td></tr>\n";
+
+    // Output any other meta data.
+
+    for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
+         I!=E; ++I) {
+      os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
+    }
+
+    os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
+          "<h3>Annotated Source Code</h3>\n";
+
+    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
+  }
+
+  // Embed meta-data tags.
+  {
+    std::string s;
+    llvm::raw_string_ostream os(s);
+
+    const std::string& BugDesc = D.getDescription();
+    if (!BugDesc.empty())
+      os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
+
+    const std::string& BugType = D.getBugType();
+    if (!BugType.empty())
+      os << "\n<!-- BUGTYPE " << BugType << " -->\n";
+
+    const std::string& BugCategory = D.getCategory();
+    if (!BugCategory.empty())
+      os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
+
+    os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
+
+    os << "\n<!-- BUGLINE "
+       << D.back()->getLocation().asLocation().getInstantiationLineNumber()
+       << " -->\n";
+
+    os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
+
+    // Mark the end of the tags.
+    os << "\n<!-- BUGMETAEND -->\n";
+
+    // Insert the text.
+    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
+  }
+
+  // Add CSS, header, and footer.
+
+  html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
+
+  // Get the rewrite buffer.
+  const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);
+
+  if (!Buf) {
+    llvm::errs() << "warning: no diagnostics generated for main file.\n";
+    return;
+  }
+
+  // Create a path for the target HTML file.
+  llvm::sys::Path F(FilePrefix);
+  F.makeUnique(false, NULL);
+
+  // Rename the file with an HTML extension.
+  llvm::sys::Path H(F);
+  H.appendSuffix("html");
+  F.renamePathOnDisk(H, NULL);
+
+  std::string ErrorMsg;
+  llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);
+
+  if (!ErrorMsg.empty()) {
+    llvm::errs() << "warning: could not create file '" << F.str()
+                 << "'\n";
+    return;
+  }
+
+  if (FilesMade)
+    FilesMade->push_back(llvm::sys::path::filename(H.str()));
+
+  // Emit the HTML to disk.
+  for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
+      os << *I;
+}
+
+void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
+                                  const PathDiagnosticPiece& P,
+                                  unsigned num, unsigned max) {
+
+  // For now, just draw a box above the line in question, and emit the
+  // warning.
+  FullSourceLoc Pos = P.getLocation().asLocation();
+
+  if (!Pos.isValid())
+    return;
+
+  SourceManager &SM = R.getSourceMgr();
+  assert(&Pos.getManager() == &SM && "SourceManagers are different!");
+  std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedInstantiationLoc(Pos);
+
+  if (LPosInfo.first != BugFileID)
+    return;
+
+  const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first);
+  const char* FileStart = Buf->getBufferStart();
+
+  // Compute the column number.  Rewind from the current position to the start
+  // of the line.
+  unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second);
+  const char *TokInstantiationPtr =Pos.getInstantiationLoc().getCharacterData();
+  const char *LineStart = TokInstantiationPtr-ColNo;
+
+  // Compute LineEnd.
+  const char *LineEnd = TokInstantiationPtr;
+  const char* FileEnd = Buf->getBufferEnd();
+  while (*LineEnd != '\n' && LineEnd != FileEnd)
+    ++LineEnd;
+
+  // Compute the margin offset by counting tabs and non-tabs.
+  unsigned PosNo = 0;
+  for (const char* c = LineStart; c != TokInstantiationPtr; ++c)
+    PosNo += *c == '\t' ? 8 : 1;
+
+  // Create the html for the message.
+
+  const char *Kind = 0;
+  switch (P.getKind()) {
+  case PathDiagnosticPiece::Event:  Kind = "Event"; break;
+  case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
+    // Setting Kind to "Control" is intentional.
+  case PathDiagnosticPiece::Macro: Kind = "Control"; break;
+  }
+
+  std::string sbuf;
+  llvm::raw_string_ostream os(sbuf);
+
+  os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
+
+  if (num == max)
+    os << "EndPath";
+  else
+    os << "Path" << num;
+
+  os << "\" class=\"msg";
+  if (Kind)
+    os << " msg" << Kind;
+  os << "\" style=\"margin-left:" << PosNo << "ex";
+
+  // Output a maximum size.
+  if (!isa<PathDiagnosticMacroPiece>(P)) {
+    // Get the string and determining its maximum substring.
+    const std::string& Msg = P.getString();
+    unsigned max_token = 0;
+    unsigned cnt = 0;
+    unsigned len = Msg.size();
+
+    for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
+      switch (*I) {
+      default:
+        ++cnt;
+        continue;
+      case ' ':
+      case '\t':
+      case '\n':
+        if (cnt > max_token) max_token = cnt;
+        cnt = 0;
+      }
+
+    if (cnt > max_token)
+      max_token = cnt;
+
+    // Determine the approximate size of the message bubble in em.
+    unsigned em;
+    const unsigned max_line = 120;
+
+    if (max_token >= max_line)
+      em = max_token / 2;
+    else {
+      unsigned characters = max_line;
+      unsigned lines = len / max_line;
+
+      if (lines > 0) {
+        for (; characters > max_token; --characters)
+          if (len / characters > lines) {
+            ++characters;
+            break;
+          }
+      }
+
+      em = characters / 2;
+    }
+
+    if (em < max_line/2)
+      os << "; max-width:" << em << "em";
+  }
+  else
+    os << "; max-width:100em";
+
+  os << "\">";
+
+  if (max > 1) {
+    os << "<table class=\"msgT\"><tr><td valign=\"top\">";
+    os << "<div class=\"PathIndex";
+    if (Kind) os << " PathIndex" << Kind;
+    os << "\">" << num << "</div>";
+    os << "</td><td>";
+  }
+
+  if (const PathDiagnosticMacroPiece *MP =
+        dyn_cast<PathDiagnosticMacroPiece>(&P)) {
+
+    os << "Within the expansion of the macro '";
+
+    // Get the name of the macro by relexing it.
+    {
+      FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc();
+      assert(L.isFileID());
+      llvm::StringRef BufferInfo = L.getBufferData();
+      const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data();
+      Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(),
+                     MacroName, BufferInfo.end());
+
+      Token TheTok;
+      rawLexer.LexFromRawLexer(TheTok);
+      for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i)
+        os << MacroName[i];
+    }
+
+    os << "':\n";
+
+    if (max > 1)
+      os << "</td></tr></table>";
+
+    // Within a macro piece.  Write out each event.
+    ProcessMacroPiece(os, *MP, 0);
+  }
+  else {
+    os << html::EscapeText(P.getString());
+
+    if (max > 1)
+      os << "</td></tr></table>";
+  }
+
+  os << "</div></td></tr>";
+
+  // Insert the new html.
+  unsigned DisplayPos = LineEnd - FileStart;
+  SourceLocation Loc =
+    SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
+
+  R.InsertTextBefore(Loc, os.str());
+
+  // Now highlight the ranges.
+  for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
+        I != E; ++I)
+    HighlightRange(R, LPosInfo.first, *I);
+
+#if 0
+  // If there is a code insertion hint, insert that code.
+  // FIXME: This code is disabled because it seems to mangle the HTML
+  // output. I'm leaving it here because it's generally the right idea,
+  // but needs some help from someone more familiar with the rewriter.
+  for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end();
+       Hint != HintEnd; ++Hint) {
+    if (Hint->RemoveRange.isValid()) {
+      HighlightRange(R, LPosInfo.first, Hint->RemoveRange,
+                     "<span class=\"CodeRemovalHint\">", "</span>");
+    }
+    if (Hint->InsertionLoc.isValid()) {
+      std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true);
+      EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode
+        + "</span>";
+      R.InsertTextBefore(Hint->InsertionLoc, EscapedCode);
+    }
+  }
+#endif
+}
+
+static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
+  unsigned x = n % ('z' - 'a');
+  n /= 'z' - 'a';
+
+  if (n > 0)
+    EmitAlphaCounter(os, n);
+
+  os << char('a' + x);
+}
+
+unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
+                                            const PathDiagnosticMacroPiece& P,
+                                            unsigned num) {
+
+  for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+        I!=E; ++I) {
+
+    if (const PathDiagnosticMacroPiece *MP =
+          dyn_cast<PathDiagnosticMacroPiece>(*I)) {
+      num = ProcessMacroPiece(os, *MP, num);
+      continue;
+    }
+
+    if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) {
+      os << "<div class=\"msg msgEvent\" style=\"width:94%; "
+            "margin-left:5px\">"
+            "<table class=\"msgT\"><tr>"
+            "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
+      EmitAlphaCounter(os, num++);
+      os << "</div></td><td valign=\"top\">"
+         << html::EscapeText(EP->getString())
+         << "</td></tr></table></div>\n";
+    }
+  }
+
+  return num;
+}
+
+void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
+                                     SourceRange Range,
+                                     const char *HighlightStart,
+                                     const char *HighlightEnd) {
+  SourceManager &SM = R.getSourceMgr();
+  const LangOptions &LangOpts = R.getLangOpts();
+
+  SourceLocation InstantiationStart = SM.getInstantiationLoc(Range.getBegin());
+  unsigned StartLineNo = SM.getInstantiationLineNumber(InstantiationStart);
+
+  SourceLocation InstantiationEnd = SM.getInstantiationLoc(Range.getEnd());
+  unsigned EndLineNo = SM.getInstantiationLineNumber(InstantiationEnd);
+
+  if (EndLineNo < StartLineNo)
+    return;
+
+  if (SM.getFileID(InstantiationStart) != BugFileID ||
+      SM.getFileID(InstantiationEnd) != BugFileID)
+    return;
+
+  // Compute the column number of the end.
+  unsigned EndColNo = SM.getInstantiationColumnNumber(InstantiationEnd);
+  unsigned OldEndColNo = EndColNo;
+
+  if (EndColNo) {
+    // Add in the length of the token, so that we cover multi-char tokens.
+    EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1;
+  }
+
+  // Highlight the range.  Make the span tag the outermost tag for the
+  // selected range.
+
+  SourceLocation E =
+    InstantiationEnd.getFileLocWithOffset(EndColNo - OldEndColNo);
+
+  html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
+}
diff --git a/lib/StaticAnalyzer/Makefile b/lib/StaticAnalyzer/Makefile
new file mode 100644 (file)
index 0000000..08ace28
--- /dev/null
@@ -0,0 +1,19 @@
+##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
+# 
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 
+##===----------------------------------------------------------------------===##
+#
+# This implements analyses built on top of source-level CFGs. 
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangStaticAnalyzerCore
+PARALLEL_DIRS := Checkers
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/StaticAnalyzer/ManagerRegistry.cpp b/lib/StaticAnalyzer/ManagerRegistry.cpp
new file mode 100644 (file)
index 0000000..3f9ed61
--- /dev/null
@@ -0,0 +1,21 @@
+//===- ManagerRegistry.cpp - Pluggble Analyzer module creators --*- 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 pluggable analyzer module creators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/ManagerRegistry.h"
+
+using namespace clang;
+using namespace ento;
+
+StoreManagerCreator ManagerRegistry::StoreMgrCreator = 0;
+
+ConstraintManagerCreator ManagerRegistry::ConstraintMgrCreator = 0;
diff --git a/lib/StaticAnalyzer/MemRegion.cpp b/lib/StaticAnalyzer/MemRegion.cpp
new file mode 100644 (file)
index 0000000..e465224
--- /dev/null
@@ -0,0 +1,987 @@
+//== MemRegion.cpp - Abstract memory regions for static analysis --*- 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 MemRegion and its subclasses.  MemRegion defines a
+//  partially-typed abstraction of memory useful for path-sensitive dataflow
+//  analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/RecordLayout.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// MemRegion Construction.
+//===----------------------------------------------------------------------===//
+
+template<typename RegionTy> struct MemRegionManagerTrait;
+
+template <typename RegionTy, typename A1>
+RegionTy* MemRegionManager::getRegion(const A1 a1) {
+
+  const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
+  MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1);
+
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, a1, superRegion);
+  void* InsertPos;
+  RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+                                                                   InsertPos));
+
+  if (!R) {
+    R = (RegionTy*) A.Allocate<RegionTy>();
+    new (R) RegionTy(a1, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+template <typename RegionTy, typename A1>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1,
+                                         const MemRegion *superRegion) {
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, a1, superRegion);
+  void* InsertPos;
+  RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+                                                                   InsertPos));
+
+  if (!R) {
+    R = (RegionTy*) A.Allocate<RegionTy>();
+    new (R) RegionTy(a1, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) {
+
+  const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion =
+  MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2);
+
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+  void* InsertPos;
+  RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+                                                                   InsertPos));
+
+  if (!R) {
+    R = (RegionTy*) A.Allocate<RegionTy>();
+    new (R) RegionTy(a1, a2, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+template <typename RegionTy, typename A1, typename A2>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2,
+                                         const MemRegion *superRegion) {
+
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, a1, a2, superRegion);
+  void* InsertPos;
+  RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+                                                                   InsertPos));
+
+  if (!R) {
+    R = (RegionTy*) A.Allocate<RegionTy>();
+    new (R) RegionTy(a1, a2, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+template <typename RegionTy, typename A1, typename A2, typename A3>
+RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3,
+                                         const MemRegion *superRegion) {
+
+  llvm::FoldingSetNodeID ID;
+  RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion);
+  void* InsertPos;
+  RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID,
+                                                                   InsertPos));
+
+  if (!R) {
+    R = (RegionTy*) A.Allocate<RegionTy>();
+    new (R) RegionTy(a1, a2, a3, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+//===----------------------------------------------------------------------===//
+// Object destruction.
+//===----------------------------------------------------------------------===//
+
+MemRegion::~MemRegion() {}
+
+MemRegionManager::~MemRegionManager() {
+  // All regions and their data are BumpPtrAllocated.  No need to call
+  // their destructors.
+}
+
+//===----------------------------------------------------------------------===//
+// Basic methods.
+//===----------------------------------------------------------------------===//
+
+bool SubRegion::isSubRegionOf(const MemRegion* R) const {
+  const MemRegion* r = getSuperRegion();
+  while (r != 0) {
+    if (r == R)
+      return true;
+    if (const SubRegion* sr = dyn_cast<SubRegion>(r))
+      r = sr->getSuperRegion();
+    else
+      break;
+  }
+  return false;
+}
+
+MemRegionManager* SubRegion::getMemRegionManager() const {
+  const SubRegion* r = this;
+  do {
+    const MemRegion *superRegion = r->getSuperRegion();
+    if (const SubRegion *sr = dyn_cast<SubRegion>(superRegion)) {
+      r = sr;
+      continue;
+    }
+    return superRegion->getMemRegionManager();
+  } while (1);
+}
+
+const StackFrameContext *VarRegion::getStackFrame() const {
+  const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace());
+  return SSR ? SSR->getStackFrame() : NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Region extents.
+//===----------------------------------------------------------------------===//
+
+DefinedOrUnknownSVal DeclRegion::getExtent(SValBuilder &svalBuilder) const {
+  ASTContext& Ctx = svalBuilder.getContext();
+  QualType T = getDesugaredValueType(Ctx);
+
+  if (isa<VariableArrayType>(T))
+    return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this));
+  if (isa<IncompleteArrayType>(T))
+    return UnknownVal();
+
+  CharUnits size = Ctx.getTypeSizeInChars(T);
+  QualType sizeTy = svalBuilder.getArrayIndexType();
+  return svalBuilder.makeIntVal(size.getQuantity(), sizeTy);
+}
+
+DefinedOrUnknownSVal FieldRegion::getExtent(SValBuilder &svalBuilder) const {
+  DefinedOrUnknownSVal Extent = DeclRegion::getExtent(svalBuilder);
+
+  // A zero-length array at the end of a struct often stands for dynamically-
+  // allocated extra memory.
+  if (Extent.isZeroConstant()) {
+    QualType T = getDesugaredValueType(svalBuilder.getContext());
+
+    if (isa<ConstantArrayType>(T))
+      return UnknownVal();
+  }
+
+  return Extent;
+}
+
+DefinedOrUnknownSVal AllocaRegion::getExtent(SValBuilder &svalBuilder) const {
+  return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this));
+}
+
+DefinedOrUnknownSVal SymbolicRegion::getExtent(SValBuilder &svalBuilder) const {
+  return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this));
+}
+
+DefinedOrUnknownSVal StringRegion::getExtent(SValBuilder &svalBuilder) const {
+  return svalBuilder.makeIntVal(getStringLiteral()->getByteLength()+1,
+                                svalBuilder.getArrayIndexType());
+}
+
+QualType CXXBaseObjectRegion::getValueType() const {
+  return QualType(decl->getTypeForDecl(), 0);
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling.
+//===----------------------------------------------------------------------===//
+
+void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  ID.AddInteger((unsigned)getKind());
+}
+
+void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger((unsigned)getKind());
+  ID.AddPointer(getStackFrame());
+}
+
+void StaticGlobalSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger((unsigned)getKind());
+  ID.AddPointer(getCodeRegion());
+}
+
+void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                 const StringLiteral* Str,
+                                 const MemRegion* superRegion) {
+  ID.AddInteger((unsigned) StringRegionKind);
+  ID.AddPointer(Str);
+  ID.AddPointer(superRegion);
+}
+
+void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                 const Expr* Ex, unsigned cnt,
+                                 const MemRegion *) {
+  ID.AddInteger((unsigned) AllocaRegionKind);
+  ID.AddPointer(Ex);
+  ID.AddInteger(cnt);
+}
+
+void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  ProfileRegion(ID, Ex, Cnt, superRegion);
+}
+
+void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
+}
+
+void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                          const CompoundLiteralExpr* CL,
+                                          const MemRegion* superRegion) {
+  ID.AddInteger((unsigned) CompoundLiteralRegionKind);
+  ID.AddPointer(CL);
+  ID.AddPointer(superRegion);
+}
+
+void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                  const PointerType *PT,
+                                  const MemRegion *sRegion) {
+  ID.AddInteger((unsigned) CXXThisRegionKind);
+  ID.AddPointer(PT);
+  ID.AddPointer(sRegion);
+}
+
+void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
+}
+
+void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+                               const MemRegion* superRegion, Kind k) {
+  ID.AddInteger((unsigned) k);
+  ID.AddPointer(D);
+  ID.AddPointer(superRegion);
+}
+
+void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  DeclRegion::ProfileRegion(ID, D, superRegion, getKind());
+}
+
+void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  VarRegion::ProfileRegion(ID, getDecl(), superRegion);
+}
+
+void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym,
+                                   const MemRegion *sreg) {
+  ID.AddInteger((unsigned) MemRegion::SymbolicRegionKind);
+  ID.Add(sym);
+  ID.AddPointer(sreg);
+}
+
+void SymbolicRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  SymbolicRegion::ProfileRegion(ID, sym, getSuperRegion());
+}
+
+void ElementRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                  QualType ElementType, SVal Idx,
+                                  const MemRegion* superRegion) {
+  ID.AddInteger(MemRegion::ElementRegionKind);
+  ID.Add(ElementType);
+  ID.AddPointer(superRegion);
+  Idx.Profile(ID);
+}
+
+void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
+}
+
+void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                       const FunctionDecl *FD,
+                                       const MemRegion*) {
+  ID.AddInteger(MemRegion::FunctionTextRegionKind);
+  ID.AddPointer(FD);
+}
+
+void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  FunctionTextRegion::ProfileRegion(ID, FD, superRegion);
+}
+
+void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                    const BlockDecl *BD, CanQualType,
+                                    const AnalysisContext *AC,
+                                    const MemRegion*) {
+  ID.AddInteger(MemRegion::BlockTextRegionKind);
+  ID.AddPointer(BD);
+}
+
+void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
+}
+
+void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+                                    const BlockTextRegion *BC,
+                                    const LocationContext *LC,
+                                    const MemRegion *sReg) {
+  ID.AddInteger(MemRegion::BlockDataRegionKind);
+  ID.AddPointer(BC);
+  ID.AddPointer(LC);
+  ID.AddPointer(sReg);
+}
+
+void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+  BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion());
+}
+
+void CXXTempObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                        Expr const *Ex,
+                                        const MemRegion *sReg) {
+  ID.AddPointer(Ex);
+  ID.AddPointer(sReg);
+}
+
+void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, Ex, getSuperRegion());
+}
+
+void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
+                                        const CXXRecordDecl *decl,
+                                        const MemRegion *sReg) {
+  ID.AddPointer(decl);
+  ID.AddPointer(sReg);
+}
+
+void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
+  ProfileRegion(ID, decl, superRegion);
+}
+
+//===----------------------------------------------------------------------===//
+// Region pretty-printing.
+//===----------------------------------------------------------------------===//
+
+void MemRegion::dump() const {
+  dumpToStream(llvm::errs());
+}
+
+std::string MemRegion::getString() const {
+  std::string s;
+  llvm::raw_string_ostream os(s);
+  dumpToStream(os);
+  return os.str();
+}
+
+void MemRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "<Unknown Region>";
+}
+
+void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
+}
+
+void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "code{" << getDecl()->getDeclName().getAsString() << '}';
+}
+
+void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "block_code{" << (void*) this << '}';
+}
+
+void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "block_data{" << BC << '}';
+}
+
+void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
+  // FIXME: More elaborate pretty-printing.
+  os << "{ " << (void*) CL <<  " }";
+}
+
+void CXXTempObjectRegion::dumpToStream(llvm::raw_ostream &os) const {
+  os << "temp_object";
+}
+
+void CXXBaseObjectRegion::dumpToStream(llvm::raw_ostream &os) const {
+  os << "base " << decl->getName();
+}
+
+void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const {
+  os << "this";
+}
+
+void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "element{" << superRegion << ','
+     << Index << ',' << getElementType().getAsString() << '}';
+}
+
+void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << superRegion << "->" << getDecl();
+}
+
+void NonStaticGlobalSpaceRegion::dumpToStream(llvm::raw_ostream &os) const {
+  os << "NonStaticGlobalSpaceRegion";
+}
+
+void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "ivar{" << superRegion << ',' << getDecl() << '}';
+}
+
+void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
+  Str->printPretty(os, 0, PrintingPolicy(getContext().getLangOptions()));
+}
+
+void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << "SymRegion{" << sym << '}';
+}
+
+void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
+  os << cast<VarDecl>(D);
+}
+
+void RegionRawOffset::dump() const {
+  dumpToStream(llvm::errs());
+}
+
+void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const {
+  os << "raw_offset{" << getRegion() << ',' << getByteOffset() << '}';
+}
+
+void StaticGlobalSpaceRegion::dumpToStream(llvm::raw_ostream &os) const {
+  os << "StaticGlobalsMemSpace{" << CR << '}';
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager methods.
+//===----------------------------------------------------------------------===//
+
+template <typename REG>
+const REG *MemRegionManager::LazyAllocate(REG*& region) {
+  if (!region) {
+    region = (REG*) A.Allocate<REG>();
+    new (region) REG(this);
+  }
+
+  return region;
+}
+
+template <typename REG, typename ARG>
+const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {
+  if (!region) {
+    region = (REG*) A.Allocate<REG>();
+    new (region) REG(this, a);
+  }
+
+  return region;
+}
+
+const StackLocalsSpaceRegion*
+MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {
+  assert(STC);
+  StackLocalsSpaceRegion *&R = StackLocalsSpaceRegions[STC];
+
+  if (R)
+    return R;
+
+  R = A.Allocate<StackLocalsSpaceRegion>();
+  new (R) StackLocalsSpaceRegion(this, STC);
+  return R;
+}
+
+const StackArgumentsSpaceRegion *
+MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {
+  assert(STC);
+  StackArgumentsSpaceRegion *&R = StackArgumentsSpaceRegions[STC];
+
+  if (R)
+    return R;
+
+  R = A.Allocate<StackArgumentsSpaceRegion>();
+  new (R) StackArgumentsSpaceRegion(this, STC);
+  return R;
+}
+
+const GlobalsSpaceRegion
+*MemRegionManager::getGlobalsRegion(const CodeTextRegion *CR) {
+  if (!CR)
+    return LazyAllocate(globals);
+
+  StaticGlobalSpaceRegion *&R = StaticsGlobalSpaceRegions[CR];
+  if (R)
+    return R;
+
+  R = A.Allocate<StaticGlobalSpaceRegion>();
+  new (R) StaticGlobalSpaceRegion(this, CR);
+  return R;
+}
+
+const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
+  return LazyAllocate(heap);
+}
+
+const MemSpaceRegion *MemRegionManager::getUnknownRegion() {
+  return LazyAllocate(unknown);
+}
+
+const MemSpaceRegion *MemRegionManager::getCodeRegion() {
+  return LazyAllocate(code);
+}
+
+//===----------------------------------------------------------------------===//
+// Constructing regions.
+//===----------------------------------------------------------------------===//
+
+const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str){
+  return getSubRegion<StringRegion>(Str, getGlobalsRegion());
+}
+
+const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
+                                                const LocationContext *LC) {
+  const MemRegion *sReg = 0;
+
+  if (D->hasGlobalStorage() && !D->isStaticLocal())
+    sReg = getGlobalsRegion();
+  else {
+    // FIXME: Once we implement scope handling, we will need to properly lookup
+    // 'D' to the proper LocationContext.
+    const DeclContext *DC = D->getDeclContext();
+    const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC);
+
+    if (!STC)
+      sReg = getUnknownRegion();
+    else {
+      if (D->hasLocalStorage()) {
+        sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)
+               ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC))
+               : static_cast<const MemRegion*>(getStackLocalsRegion(STC));
+      }
+      else {
+        assert(D->isStaticLocal());
+        const Decl *D = STC->getDecl();
+        if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+          sReg = getGlobalsRegion(getFunctionTextRegion(FD));
+        else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+          const BlockTextRegion *BTR =
+            getBlockTextRegion(BD,
+                     C.getCanonicalType(BD->getSignatureAsWritten()->getType()),
+                     STC->getAnalysisContext());
+          sReg = getGlobalsRegion(BTR);
+        }
+        else {
+          // FIXME: For ObjC-methods, we need a new CodeTextRegion.  For now
+          // just use the main global memspace.
+          sReg = getGlobalsRegion();
+        }
+      }
+    }
+  }
+
+  return getSubRegion<VarRegion>(D, sReg);
+}
+
+const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
+                                                const MemRegion *superR) {
+  return getSubRegion<VarRegion>(D, superR);
+}
+
+const BlockDataRegion *
+MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+                                     const LocationContext *LC) {
+  const MemRegion *sReg = 0;
+
+  if (LC) {
+    // FIXME: Once we implement scope handling, we want the parent region
+    // to be the scope.
+    const StackFrameContext *STC = LC->getCurrentStackFrame();
+    assert(STC);
+    sReg = getStackLocalsRegion(STC);
+  }
+  else {
+    // We allow 'LC' to be NULL for cases where want BlockDataRegions
+    // without context-sensitivity.
+    sReg = getUnknownRegion();
+  }
+
+  return getSubRegion<BlockDataRegion>(BC, LC, sReg);
+}
+
+const CompoundLiteralRegion*
+MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+                                           const LocationContext *LC) {
+
+  const MemRegion *sReg = 0;
+
+  if (CL->isFileScope())
+    sReg = getGlobalsRegion();
+  else {
+    const StackFrameContext *STC = LC->getCurrentStackFrame();
+    assert(STC);
+    sReg = getStackLocalsRegion(STC);
+  }
+
+  return getSubRegion<CompoundLiteralRegion>(CL, sReg);
+}
+
+const ElementRegion*
+MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
+                                   const MemRegion* superRegion,
+                                   ASTContext& Ctx){
+
+  QualType T = Ctx.getCanonicalType(elementType).getUnqualifiedType();
+
+  llvm::FoldingSetNodeID ID;
+  ElementRegion::ProfileRegion(ID, T, Idx, superRegion);
+
+  void* InsertPos;
+  MemRegion* data = Regions.FindNodeOrInsertPos(ID, InsertPos);
+  ElementRegion* R = cast_or_null<ElementRegion>(data);
+
+  if (!R) {
+    R = (ElementRegion*) A.Allocate<ElementRegion>();
+    new (R) ElementRegion(T, Idx, superRegion);
+    Regions.InsertNode(R, InsertPos);
+  }
+
+  return R;
+}
+
+const FunctionTextRegion *
+MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
+  return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
+}
+
+const BlockTextRegion *
+MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy,
+                                     AnalysisContext *AC) {
+  return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion());
+}
+
+
+/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
+  return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
+}
+
+const FieldRegion*
+MemRegionManager::getFieldRegion(const FieldDecl* d,
+                                 const MemRegion* superRegion){
+  return getSubRegion<FieldRegion>(d, superRegion);
+}
+
+const ObjCIvarRegion*
+MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
+                                    const MemRegion* superRegion) {
+  return getSubRegion<ObjCIvarRegion>(d, superRegion);
+}
+
+const CXXTempObjectRegion*
+MemRegionManager::getCXXTempObjectRegion(Expr const *E,
+                                         LocationContext const *LC) {
+  const StackFrameContext *SFC = LC->getCurrentStackFrame();
+  assert(SFC);
+  return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
+}
+
+const CXXBaseObjectRegion *
+MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl,
+                                         const MemRegion *superRegion) {
+  return getSubRegion<CXXBaseObjectRegion>(decl, superRegion);
+}
+
+const CXXThisRegion*
+MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
+                                   const LocationContext *LC) {
+  const StackFrameContext *STC = LC->getCurrentStackFrame();
+  assert(STC);
+  const PointerType *PT = thisPointerTy->getAs<PointerType>();
+  assert(PT);
+  return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
+}
+
+const AllocaRegion*
+MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt,
+                                  const LocationContext *LC) {
+  const StackFrameContext *STC = LC->getCurrentStackFrame();
+  assert(STC);
+  return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC));
+}
+
+const MemSpaceRegion *MemRegion::getMemorySpace() const {
+  const MemRegion *R = this;
+  const SubRegion* SR = dyn_cast<SubRegion>(this);
+
+  while (SR) {
+    R = SR->getSuperRegion();
+    SR = dyn_cast<SubRegion>(R);
+  }
+
+  return dyn_cast<MemSpaceRegion>(R);
+}
+
+bool MemRegion::hasStackStorage() const {
+  return isa<StackSpaceRegion>(getMemorySpace());
+}
+
+bool MemRegion::hasStackNonParametersStorage() const {
+  return isa<StackLocalsSpaceRegion>(getMemorySpace());
+}
+
+bool MemRegion::hasStackParametersStorage() const {
+  return isa<StackArgumentsSpaceRegion>(getMemorySpace());
+}
+
+bool MemRegion::hasGlobalsOrParametersStorage() const {
+  const MemSpaceRegion *MS = getMemorySpace();
+  return isa<StackArgumentsSpaceRegion>(MS) ||
+         isa<GlobalsSpaceRegion>(MS);
+}
+
+// getBaseRegion strips away all elements and fields, and get the base region
+// of them.
+const MemRegion *MemRegion::getBaseRegion() const {
+  const MemRegion *R = this;
+  while (true) {
+    switch (R->getKind()) {
+      case MemRegion::ElementRegionKind:
+      case MemRegion::FieldRegionKind:
+      case MemRegion::ObjCIvarRegionKind:
+        R = cast<SubRegion>(R)->getSuperRegion();
+        continue;
+      default:
+        break;
+    }
+    break;
+  }
+  return R;
+}
+
+//===----------------------------------------------------------------------===//
+// View handling.
+//===----------------------------------------------------------------------===//
+
+const MemRegion *MemRegion::StripCasts() const {
+  const MemRegion *R = this;
+  while (true) {
+    if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+      // FIXME: generalize.  Essentially we want to strip away ElementRegions
+      // that were layered on a symbolic region because of casts.  We only
+      // want to strip away ElementRegions, however, where the index is 0.
+      SVal index = ER->getIndex();
+      if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
+        if (CI->getValue().getSExtValue() == 0) {
+          R = ER->getSuperRegion();
+          continue;
+        }
+      }
+    }
+    break;
+  }
+  return R;
+}
+
+// FIXME: Merge with the implementation of the same method in Store.cpp
+static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
+  if (const RecordType *RT = Ty->getAs<RecordType>()) {
+    const RecordDecl *D = RT->getDecl();
+    if (!D->getDefinition())
+      return false;
+  }
+
+  return true;
+}
+
+RegionRawOffset ElementRegion::getAsArrayOffset() const {
+  CharUnits offset = CharUnits::Zero();
+  const ElementRegion *ER = this;
+  const MemRegion *superR = NULL;
+  ASTContext &C = getContext();
+
+  // FIXME: Handle multi-dimensional arrays.
+
+  while (ER) {
+    superR = ER->getSuperRegion();
+
+    // FIXME: generalize to symbolic offsets.
+    SVal index = ER->getIndex();
+    if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
+      // Update the offset.
+      int64_t i = CI->getValue().getSExtValue();
+
+      if (i != 0) {
+        QualType elemType = ER->getElementType();
+
+        // If we are pointing to an incomplete type, go no further.
+        if (!IsCompleteType(C, elemType)) {
+          superR = ER;
+          break;
+        }
+
+        CharUnits size = C.getTypeSizeInChars(elemType);
+        offset += (i * size);
+      }
+
+      // Go to the next ElementRegion (if any).
+      ER = dyn_cast<ElementRegion>(superR);
+      continue;
+    }
+
+    return NULL;
+  }
+
+  assert(superR && "super region cannot be NULL");
+  return RegionRawOffset(superR, offset.getQuantity());
+}
+
+RegionOffset MemRegion::getAsOffset() const {
+  const MemRegion *R = this;
+  int64_t Offset = 0;
+
+  while (1) {
+    switch (R->getKind()) {
+    default:
+      return RegionOffset(0);
+    case SymbolicRegionKind:
+    case AllocaRegionKind:
+    case CompoundLiteralRegionKind:
+    case CXXThisRegionKind:
+    case StringRegionKind:
+    case VarRegionKind:
+    case CXXTempObjectRegionKind:
+      goto Finish;
+    case ElementRegionKind: {
+      const ElementRegion *ER = cast<ElementRegion>(R);
+      QualType EleTy = ER->getValueType();
+
+      if (!IsCompleteType(getContext(), EleTy))
+        return RegionOffset(0);
+
+      SVal Index = ER->getIndex();
+      if (const nonloc::ConcreteInt *CI=dyn_cast<nonloc::ConcreteInt>(&Index)) {
+        int64_t i = CI->getValue().getSExtValue();
+        CharUnits Size = getContext().getTypeSizeInChars(EleTy);
+        Offset += i * Size.getQuantity() * 8;
+      } else {
+        // We cannot compute offset for non-concrete index.
+        return RegionOffset(0);
+      }
+      R = ER->getSuperRegion();
+      break;
+    }
+    case FieldRegionKind: {
+      const FieldRegion *FR = cast<FieldRegion>(R);
+      const RecordDecl *RD = FR->getDecl()->getParent();
+      if (!RD->isDefinition())
+        // We cannot compute offset for incomplete type.
+        return RegionOffset(0);
+      // Get the field number.
+      unsigned idx = 0;
+      for (RecordDecl::field_iterator FI = RD->field_begin(), 
+             FE = RD->field_end(); FI != FE; ++FI, ++idx)
+        if (FR->getDecl() == *FI)
+          break;
+
+      const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+      // This is offset in bits.
+      Offset += Layout.getFieldOffset(idx);
+      R = FR->getSuperRegion();
+      break;
+    }
+    }
+  }
+
+ Finish:
+  return RegionOffset(R, Offset);
+}
+
+//===----------------------------------------------------------------------===//
+// BlockDataRegion
+//===----------------------------------------------------------------------===//
+
+void BlockDataRegion::LazyInitializeReferencedVars() {
+  if (ReferencedVars)
+    return;
+
+  AnalysisContext *AC = getCodeRegion()->getAnalysisContext();
+  AnalysisContext::referenced_decls_iterator I, E;
+  llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
+
+  if (I == E) {
+    ReferencedVars = (void*) 0x1;
+    return;
+  }
+
+  MemRegionManager &MemMgr = *getMemRegionManager();
+  llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
+  BumpVectorContext BC(A);
+
+  typedef BumpVector<const MemRegion*> VarVec;
+  VarVec *BV = (VarVec*) A.Allocate<VarVec>();
+  new (BV) VarVec(BC, E - I);
+
+  for ( ; I != E; ++I) {
+    const VarDecl *VD = *I;
+    const VarRegion *VR = 0;
+
+    if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage())
+      VR = MemMgr.getVarRegion(VD, this);
+    else {
+      if (LC)
+        VR = MemMgr.getVarRegion(VD, LC);
+      else {
+        VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+      }
+    }
+
+    assert(VR);
+    BV->push_back(VR, BC);
+  }
+
+  ReferencedVars = BV;
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_begin() const {
+  const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+  BumpVector<const MemRegion*> *Vec =
+    static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+  return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
+                                                   NULL : Vec->begin());
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_end() const {
+  const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+  BumpVector<const MemRegion*> *Vec =
+    static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+  return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ?
+                                                   NULL : Vec->end());
+}
diff --git a/lib/StaticAnalyzer/PathDiagnostic.cpp b/lib/StaticAnalyzer/PathDiagnostic.cpp
new file mode 100644 (file)
index 0000000..f05dec8
--- /dev/null
@@ -0,0 +1,279 @@
+//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- 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 PathDiagnostic-related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Casting.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::dyn_cast;
+using llvm::isa;
+
+bool PathDiagnosticMacroPiece::containsEvent() const {
+  for (const_iterator I = begin(), E = end(); I!=E; ++I) {
+    if (isa<PathDiagnosticEventPiece>(*I))
+      return true;
+
+    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
+      if (MP->containsEvent())
+        return true;
+  }
+
+  return false;
+}
+
+static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
+  for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
+    if (s[i - 1] != '.')
+      return s.substr(0, i);
+  return "";
+}
+
+PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
+                                         Kind k, DisplayHint hint)
+  : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
+
+PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
+  : kind(k), Hint(hint) {}
+
+PathDiagnosticPiece::~PathDiagnosticPiece() {}
+PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
+PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
+
+PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
+  for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
+}
+
+PathDiagnostic::PathDiagnostic() : Size(0) {}
+
+PathDiagnostic::~PathDiagnostic() {
+  for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
+}
+
+void PathDiagnostic::resetPath(bool deletePieces) {
+  Size = 0;
+
+  if (deletePieces)
+    for (iterator I=begin(), E=end(); I!=E; ++I)
+      delete &*I;
+
+  path.clear();
+}
+
+
+PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
+                               llvm::StringRef category)
+  : Size(0),
+    BugType(StripTrailingDots(bugtype)),
+    Desc(StripTrailingDots(desc)),
+    Category(StripTrailingDots(category)) {}
+
+void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
+                                            const DiagnosticInfo &Info) {
+  // Default implementation (Warnings/errors count).
+  DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
+
+  // Create a PathDiagnostic with a single piece.
+
+  PathDiagnostic* D = new PathDiagnostic();
+
+  const char *LevelStr;
+  switch (DiagLevel) {
+  default:
+  case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
+  case Diagnostic::Note:    LevelStr = "note: "; break;
+  case Diagnostic::Warning: LevelStr = "warning: "; break;
+  case Diagnostic::Error:   LevelStr = "error: "; break;
+  case Diagnostic::Fatal:   LevelStr = "fatal error: "; break;
+  }
+
+  llvm::SmallString<100> StrC;
+  StrC += LevelStr;
+  Info.FormatDiagnostic(StrC);
+
+  PathDiagnosticPiece *P =
+    new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(),
+                                               Info.getSourceManager()),
+                                 StrC.str());
+
+  for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
+    P->addRange(Info.getRange(i).getAsRange());
+  for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
+    P->addFixItHint(Info.getFixItHint(i));
+  D->push_front(P);
+
+  HandlePathDiagnostic(D);
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnosticLocation methods.
+//===----------------------------------------------------------------------===//
+
+FullSourceLoc PathDiagnosticLocation::asLocation() const {
+  assert(isValid());
+  // Note that we want a 'switch' here so that the compiler can warn us in
+  // case we add more cases.
+  switch (K) {
+    case SingleLocK:
+    case RangeK:
+      break;
+    case StmtK:
+      return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
+    case DeclK:
+      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
+  }
+
+  return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
+}
+
+PathDiagnosticRange PathDiagnosticLocation::asRange() const {
+  assert(isValid());
+  // Note that we want a 'switch' here so that the compiler can warn us in
+  // case we add more cases.
+  switch (K) {
+    case SingleLocK:
+      return PathDiagnosticRange(R, true);
+    case RangeK:
+      break;
+    case StmtK: {
+      const Stmt *S = asStmt();
+      switch (S->getStmtClass()) {
+        default:
+          break;
+        case Stmt::DeclStmtClass: {
+          const DeclStmt *DS = cast<DeclStmt>(S);
+          if (DS->isSingleDecl()) {
+            // Should always be the case, but we'll be defensive.
+            return SourceRange(DS->getLocStart(),
+                               DS->getSingleDecl()->getLocation());
+          }
+          break;
+        }
+          // FIXME: Provide better range information for different
+          //  terminators.
+        case Stmt::IfStmtClass:
+        case Stmt::WhileStmtClass:
+        case Stmt::DoStmtClass:
+        case Stmt::ForStmtClass:
+        case Stmt::ChooseExprClass:
+        case Stmt::IndirectGotoStmtClass:
+        case Stmt::SwitchStmtClass:
+        case Stmt::ConditionalOperatorClass:
+        case Stmt::ObjCForCollectionStmtClass: {
+          SourceLocation L = S->getLocStart();
+          return SourceRange(L, L);
+        }
+      }
+
+      return S->getSourceRange();
+    }
+    case DeclK:
+      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+        return MD->getSourceRange();
+      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+        if (Stmt *Body = FD->getBody())
+          return Body->getSourceRange();
+      }
+      else {
+        SourceLocation L = D->getLocation();
+        return PathDiagnosticRange(SourceRange(L, L), true);
+      }
+  }
+
+  return R;
+}
+
+void PathDiagnosticLocation::flatten() {
+  if (K == StmtK) {
+    R = asRange();
+    K = RangeK;
+    S = 0;
+    D = 0;
+  }
+  else if (K == DeclK) {
+    SourceLocation L = D->getLocation();
+    R = SourceRange(L, L);
+    K = SingleLocK;
+    S = 0;
+    D = 0;
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// FoldingSet profiling methods.
+//===----------------------------------------------------------------------===//
+
+void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger((unsigned) K);
+  switch (K) {
+    case RangeK:
+      ID.AddInteger(R.getBegin().getRawEncoding());
+      ID.AddInteger(R.getEnd().getRawEncoding());
+      break;      
+    case SingleLocK:
+      ID.AddInteger(R.getBegin().getRawEncoding());
+      break;
+    case StmtK:
+      ID.Add(S);
+      break;
+    case DeclK:
+      ID.Add(D);
+      break;
+  }
+  return;
+}
+
+void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger((unsigned) getKind());
+  ID.AddString(str);
+  // FIXME: Add profiling support for code hints.
+  ID.AddInteger((unsigned) getDisplayHint());
+  for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
+    ID.AddInteger(I->getBegin().getRawEncoding());
+    ID.AddInteger(I->getEnd().getRawEncoding());
+  }  
+}
+
+void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+  PathDiagnosticPiece::Profile(ID);
+  ID.Add(Pos);
+}
+
+void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+  PathDiagnosticPiece::Profile(ID);
+  for (const_iterator I = begin(), E = end(); I != E; ++I)
+    ID.Add(*I);
+}
+
+void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
+  PathDiagnosticSpotPiece::Profile(ID);
+  for (const_iterator I = begin(), E = end(); I != E; ++I)
+    ID.Add(**I);
+}
+
+void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
+  ID.AddInteger(Size);
+  ID.AddString(BugType);
+  ID.AddString(Desc);
+  ID.AddString(Category);
+  for (const_iterator I = begin(), E = end(); I != E; ++I)
+    ID.Add(*I);
+  
+  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
+    ID.AddString(*I);
+}
diff --git a/lib/StaticAnalyzer/PlistDiagnostics.cpp b/lib/StaticAnalyzer/PlistDiagnostics.cpp
new file mode 100644 (file)
index 0000000..ecc0cff
--- /dev/null
@@ -0,0 +1,472 @@
+//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- 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 PlistDiagnostics object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+using namespace clang;
+using namespace ento;
+using llvm::cast;
+
+typedef llvm::DenseMap<FileID, unsigned> FIDMap;
+
+namespace clang {
+  class Preprocessor;
+}
+
+namespace {
+struct CompareDiagnostics {
+  // Compare if 'X' is "<" than 'Y'.
+  bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const {
+    // First compare by location
+    const FullSourceLoc &XLoc = X->getLocation().asLocation();
+    const FullSourceLoc &YLoc = Y->getLocation().asLocation();
+    if (XLoc < YLoc)
+      return true;
+    if (XLoc != YLoc)
+      return false;
+    
+    // Next, compare by bug type.
+    llvm::StringRef XBugType = X->getBugType();
+    llvm::StringRef YBugType = Y->getBugType();
+    if (XBugType < YBugType)
+      return true;
+    if (XBugType != YBugType)
+      return false;
+    
+    // Next, compare by bug description.
+    llvm::StringRef XDesc = X->getDescription();
+    llvm::StringRef YDesc = Y->getDescription();
+    if (XDesc < YDesc)
+      return true;
+    if (XDesc != YDesc)
+      return false;
+    
+    // FIXME: Further refine by comparing PathDiagnosticPieces?
+    return false;    
+  }  
+};  
+}
+
+namespace {
+  class PlistDiagnostics : public PathDiagnosticClient {
+    std::vector<const PathDiagnostic*> BatchedDiags;
+    const std::string OutputFile;
+    const LangOptions &LangOpts;
+    llvm::OwningPtr<PathDiagnosticClient> SubPD;
+    bool flushed;
+  public:
+    PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
+                     PathDiagnosticClient *subPD);
+
+    ~PlistDiagnostics() { FlushDiagnostics(NULL); }
+
+    void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade);
+    
+    void HandlePathDiagnostic(const PathDiagnostic* D);
+    
+    virtual llvm::StringRef getName() const {
+      return "PlistDiagnostics";
+    }
+
+    PathGenerationScheme getGenerationScheme() const;
+    bool supportsLogicalOpControlFlow() const { return true; }
+    bool supportsAllBlockEdges() const { return true; }
+    virtual bool useVerboseDescription() const { return false; }
+  };
+} // end anonymous namespace
+
+PlistDiagnostics::PlistDiagnostics(const std::string& output,
+                                   const LangOptions &LO,
+                                   PathDiagnosticClient *subPD)
+  : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {}
+
+PathDiagnosticClient*
+ento::createPlistDiagnosticClient(const std::string& s, const Preprocessor &PP,
+                                  PathDiagnosticClient *subPD) {
+  return new PlistDiagnostics(s, PP.getLangOptions(), subPD);
+}
+
+PathDiagnosticClient::PathGenerationScheme
+PlistDiagnostics::getGenerationScheme() const {
+  if (const PathDiagnosticClient *PD = SubPD.get())
+    return PD->getGenerationScheme();
+
+  return Extensive;
+}
+
+static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V,
+                   const SourceManager* SM, SourceLocation L) {
+
+  FileID FID = SM->getFileID(SM->getInstantiationLoc(L));
+  FIDMap::iterator I = FIDs.find(FID);
+  if (I != FIDs.end()) return;
+  FIDs[FID] = V.size();
+  V.push_back(FID);
+}
+
+static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM,
+                       SourceLocation L) {
+  FileID FID = SM.getFileID(SM.getInstantiationLoc(L));
+  FIDMap::const_iterator I = FIDs.find(FID);
+  assert(I != FIDs.end());
+  return I->second;
+}
+
+static llvm::raw_ostream& Indent(llvm::raw_ostream& o, const unsigned indent) {
+  for (unsigned i = 0; i < indent; ++i) o << ' ';
+  return o;
+}
+
+static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM,
+                         const LangOptions &LangOpts,
+                         SourceLocation L, const FIDMap &FM,
+                         unsigned indent, bool extend = false) {
+
+  FullSourceLoc Loc(SM.getInstantiationLoc(L), const_cast<SourceManager&>(SM));
+
+  // Add in the length of the token, so that we cover multi-char tokens.
+  unsigned offset =
+    extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0;
+
+  Indent(o, indent) << "<dict>\n";
+  Indent(o, indent) << " <key>line</key><integer>"
+                    << Loc.getInstantiationLineNumber() << "</integer>\n";
+  Indent(o, indent) << " <key>col</key><integer>"
+                    << Loc.getInstantiationColumnNumber() + offset << "</integer>\n";
+  Indent(o, indent) << " <key>file</key><integer>"
+                    << GetFID(FM, SM, Loc) << "</integer>\n";
+  Indent(o, indent) << "</dict>\n";
+}
+
+static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM,
+                         const LangOptions &LangOpts,
+                         const PathDiagnosticLocation &L, const FIDMap& FM,
+                         unsigned indent, bool extend = false) {
+  EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend);
+}
+
+static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM,
+                      const LangOptions &LangOpts,
+                      PathDiagnosticRange R, const FIDMap &FM,
+                      unsigned indent) {
+  Indent(o, indent) << "<array>\n";
+  EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1);
+  EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint);
+  Indent(o, indent) << "</array>\n";
+}
+
+static llvm::raw_ostream& EmitString(llvm::raw_ostream& o,
+                                     const std::string& s) {
+  o << "<string>";
+  for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
+    char c = *I;
+    switch (c) {
+    default:   o << c; break;
+    case '&':  o << "&amp;"; break;
+    case '<':  o << "&lt;"; break;
+    case '>':  o << "&gt;"; break;
+    case '\'': o << "&apos;"; break;
+    case '\"': o << "&quot;"; break;
+    }
+  }
+  o << "</string>";
+  return o;
+}
+
+static void ReportControlFlow(llvm::raw_ostream& o,
+                              const PathDiagnosticControlFlowPiece& P,
+                              const FIDMap& FM,
+                              const SourceManager &SM,
+                              const LangOptions &LangOpts,
+                              unsigned indent) {
+
+  Indent(o, indent) << "<dict>\n";
+  ++indent;
+
+  Indent(o, indent) << "<key>kind</key><string>control</string>\n";
+
+  // Emit edges.
+  Indent(o, indent) << "<key>edges</key>\n";
+  ++indent;
+  Indent(o, indent) << "<array>\n";
+  ++indent;
+  for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end();
+       I!=E; ++I) {
+    Indent(o, indent) << "<dict>\n";
+    ++indent;
+    Indent(o, indent) << "<key>start</key>\n";
+    EmitRange(o, SM, LangOpts, I->getStart().asRange(), FM, indent+1);
+    Indent(o, indent) << "<key>end</key>\n";
+    EmitRange(o, SM, LangOpts, I->getEnd().asRange(), FM, indent+1);
+    --indent;
+    Indent(o, indent) << "</dict>\n";
+  }
+  --indent;
+  Indent(o, indent) << "</array>\n";
+  --indent;
+
+  // Output any helper text.
+  const std::string& s = P.getString();
+  if (!s.empty()) {
+    Indent(o, indent) << "<key>alternate</key>";
+    EmitString(o, s) << '\n';
+  }
+
+  --indent;
+  Indent(o, indent) << "</dict>\n";
+}
+
+static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+                        const FIDMap& FM,
+                        const SourceManager &SM,
+                        const LangOptions &LangOpts,
+                        unsigned indent) {
+
+  Indent(o, indent) << "<dict>\n";
+  ++indent;
+
+  Indent(o, indent) << "<key>kind</key><string>event</string>\n";
+
+  // Output the location.
+  FullSourceLoc L = P.getLocation().asLocation();
+
+  Indent(o, indent) << "<key>location</key>\n";
+  EmitLocation(o, SM, LangOpts, L, FM, indent);
+
+  // Output the ranges (if any).
+  PathDiagnosticPiece::range_iterator RI = P.ranges_begin(),
+  RE = P.ranges_end();
+
+  if (RI != RE) {
+    Indent(o, indent) << "<key>ranges</key>\n";
+    Indent(o, indent) << "<array>\n";
+    ++indent;
+    for (; RI != RE; ++RI)
+      EmitRange(o, SM, LangOpts, *RI, FM, indent+1);
+    --indent;
+    Indent(o, indent) << "</array>\n";
+  }
+
+  // Output the text.
+  assert(!P.getString().empty());
+  Indent(o, indent) << "<key>extended_message</key>\n";
+  Indent(o, indent);
+  EmitString(o, P.getString()) << '\n';
+
+  // Output the short text.
+  // FIXME: Really use a short string.
+  Indent(o, indent) << "<key>message</key>\n";
+  EmitString(o, P.getString()) << '\n';
+
+  // Finish up.
+  --indent;
+  Indent(o, indent); o << "</dict>\n";
+}
+
+static void ReportMacro(llvm::raw_ostream& o,
+                        const PathDiagnosticMacroPiece& P,
+                        const FIDMap& FM, const SourceManager &SM,
+                        const LangOptions &LangOpts,
+                        unsigned indent) {
+
+  for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
+       I!=E; ++I) {
+
+    switch ((*I)->getKind()) {
+    default:
+      break;
+    case PathDiagnosticPiece::Event:
+      ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts,
+                  indent);
+      break;
+    case PathDiagnosticPiece::Macro:
+      ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts,
+                  indent);
+      break;
+    }
+  }
+}
+
+static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+                       const FIDMap& FM, const SourceManager &SM,
+                       const LangOptions &LangOpts) {
+
+  unsigned indent = 4;
+
+  switch (P.getKind()) {
+  case PathDiagnosticPiece::ControlFlow:
+    ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
+                      LangOpts, indent);
+    break;
+  case PathDiagnosticPiece::Event:
+    ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts,
+                indent);
+    break;
+  case PathDiagnosticPiece::Macro:
+    ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
+                indent);
+    break;
+  }
+}
+
+void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+  if (!D)
+    return;
+
+  if (D->empty()) {
+    delete D;
+    return;
+  }
+
+  // We need to flatten the locations (convert Stmt* to locations) because
+  // the referenced statements may be freed by the time the diagnostics
+  // are emitted.
+  const_cast<PathDiagnostic*>(D)->flattenLocations();
+  BatchedDiags.push_back(D);
+}
+
+void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string>
+                                        *FilesMade) {
+  
+  if (flushed)
+    return;
+  
+  flushed = true;
+  
+  // Sort the diagnostics so that they are always emitted in a deterministic
+  // order.
+  if (!BatchedDiags.empty())
+    std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); 
+
+  // Build up a set of FIDs that we use by scanning the locations and
+  // ranges of the diagnostics.
+  FIDMap FM;
+  llvm::SmallVector<FileID, 10> Fids;
+  const SourceManager* SM = 0;
+
+  if (!BatchedDiags.empty())
+    SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager();
+
+  for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(),
+       DE = BatchedDiags.end(); DI != DE; ++DI) {
+
+    const PathDiagnostic *D = *DI;
+
+    for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I!=E; ++I) {
+      AddFID(FM, Fids, SM, I->getLocation().asLocation());
+
+      for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
+           RE=I->ranges_end(); RI!=RE; ++RI) {
+        AddFID(FM, Fids, SM, RI->getBegin());
+        AddFID(FM, Fids, SM, RI->getEnd());
+      }
+    }
+  }
+
+  // Open the file.
+  std::string ErrMsg;
+  llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg);
+  if (!ErrMsg.empty()) {
+    llvm::errs() << "warning: could not creat file: " << OutputFile << '\n';
+    return;
+  }
+
+  // Write the plist header.
+  o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+  "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
+  "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+  "<plist version=\"1.0\">\n";
+
+  // Write the root object: a <dict> containing...
+  //  - "files", an <array> mapping from FIDs to file names
+  //  - "diagnostics", an <array> containing the path diagnostics
+  o << "<dict>\n"
+       " <key>files</key>\n"
+       " <array>\n";
+
+  for (llvm::SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
+       I!=E; ++I) {
+    o << "  ";
+    EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n';
+  }
+
+  o << " </array>\n"
+       " <key>diagnostics</key>\n"
+       " <array>\n";
+
+  for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(),
+       DE = BatchedDiags.end(); DI!=DE; ++DI) {
+
+    o << "  <dict>\n"
+         "   <key>path</key>\n";
+
+    const PathDiagnostic *D = *DI;
+    // Create an owning smart pointer for 'D' just so that we auto-free it
+    // when we exit this method.
+    llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D));
+
+    o << "   <array>\n";
+
+    for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I)
+      ReportDiag(o, *I, FM, *SM, LangOpts);
+
+    o << "   </array>\n";
+
+    // Output the bug type and bug category.
+    o << "   <key>description</key>";
+    EmitString(o, D->getDescription()) << '\n';
+    o << "   <key>category</key>";
+    EmitString(o, D->getCategory()) << '\n';
+    o << "   <key>type</key>";
+    EmitString(o, D->getBugType()) << '\n';
+
+    // Output the location of the bug.
+    o << "  <key>location</key>\n";
+    EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2);
+
+    // Output the diagnostic to the sub-diagnostic client, if any.
+    if (SubPD) {
+      SubPD->HandlePathDiagnostic(OwnedD.take());
+      llvm::SmallVector<std::string, 1> SubFilesMade;
+      SubPD->FlushDiagnostics(SubFilesMade);
+
+      if (!SubFilesMade.empty()) {
+        o << "  <key>" << SubPD->getName() << "_files</key>\n";
+        o << "  <array>\n";
+        for (size_t i = 0, n = SubFilesMade.size(); i < n ; ++i)
+          o << "   <string>" << SubFilesMade[i] << "</string>\n";
+        o << "  </array>\n";
+      }
+    }
+
+    // Close up the entry.
+    o << "  </dict>\n";
+  }
+
+  o << " </array>\n";
+
+  // Finish.
+  o << "</dict>\n</plist>";
+  
+  if (FilesMade)
+    FilesMade->push_back(OutputFile);
+  
+  BatchedDiags.clear();
+}
diff --git a/lib/StaticAnalyzer/README.txt b/lib/StaticAnalyzer/README.txt
new file mode 100644 (file)
index 0000000..dd16ccc
--- /dev/null
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+// Clang Static Analyzer
+//===----------------------------------------------------------------------===//
+
+= Library Structure =
+
+The analyzer library has two layers: a (low-level) static analysis
+engine (GRExprEngine.cpp and friends), and some static checkers
+(*Checker.cpp).  The latter are built on top of the former via the
+Checker and CheckerVisitor interfaces (Checker.h and
+CheckerVisitor.h).  The Checker interface is designed to be minimal
+and simple for checker writers, and attempts to isolate them from much
+of the gore of the internal analysis engine.
+
+= How It Works =
+
+The analyzer is inspired by several foundational research papers ([1],
+[2]).  (FIXME: kremenek to add more links)
+
+In a nutshell, the analyzer is basically a source code simulator that
+traces out possible paths of execution.  The state of the program
+(values of variables and expressions) is encapsulated by the state
+(GRState).  A location in the program is called a program point
+(ProgramPoint), and the combination of state and program point is a
+node in an exploded graph (ExplodedGraph).  The term "exploded" comes
+from exploding the control-flow edges in the control-flow graph (CFG).
+
+Conceptually the analyzer does a reachability analysis through the
+ExplodedGraph.  We start at a root node, which has the entry program
+point and initial state, and then simulate transitions by analyzing
+individual expressions.  The analysis of an expression can cause the
+state to change, resulting in a new node in the ExplodedGraph with an
+updated program point and an updated state.  A bug is found by hitting
+a node that satisfies some "bug condition" (basically a violation of a
+checking invariant).
+
+The analyzer traces out multiple paths by reasoning about branches and
+then bifurcating the state: on the true branch the conditions of the
+branch are assumed to be true and on the false branch the conditions
+of the branch are assumed to be false.  Such "assumptions" create
+constraints on the values of the program, and those constraints are
+recorded in the GRState object (and are manipulated by the
+ConstraintManager).  If assuming the conditions of a branch would
+cause the constraints to be unsatisfiable, the branch is considered
+infeasible and that path is not taken.  This is how we get
+path-sensitivity.  We reduce exponential blow-up by caching nodes.  If
+a new node with the same state and program point as an existing node
+would get generated, the path "caches out" and we simply reuse the
+existing node.  Thus the ExplodedGraph is not a DAG; it can contain
+cycles as paths loop back onto each other and cache out.
+
+GRState and ExplodedNodes are basically immutable once created.  Once
+one creates a GRState, you need to create a new one to get a new
+GRState.  This immutability is key since the ExplodedGraph represents
+the behavior of the analyzed program from the entry point.  To
+represent these efficiently, we use functional data structures (e.g.,
+ImmutableMaps) which share data between instances.
+
+Finally, individual Checkers work by also manipulating the analysis
+state.  The analyzer engine talks to them via a visitor interface.
+For example, the PreVisitCallExpr() method is called by GRExprEngine
+to tell the Checker that we are about to analyze a CallExpr, and the
+checker is asked to check for any preconditions that might not be
+satisfied.  The checker can do nothing, or it can generate a new
+GRState and ExplodedNode which contains updated checker state.  If it
+finds a bug, it can tell the BugReporter object about the bug,
+providing it an ExplodedNode which is the last node in the path that
+triggered the problem.
+
+= Working on the Analyzer =
+
+If you are interested in bringing up support for C++ expressions, the
+best place to look is the visitation logic in GRExprEngine, which
+handles the simulation of individual expressions.  There are plenty of
+examples there of how other expressions are handled.
+
+If you are interested in writing checkers, look at the Checker and
+CheckerVisitor interfaces (Checker.h and CheckerVisitor.h).  Also look
+at the files named *Checker.cpp for examples on how you can implement
+these interfaces.
+
+= Debugging the Analyzer =
+
+There are some useful command-line options for debugging.  For example:
+
+$ clang -cc1 -help | grep analyze
+ -analyze-function <value>
+ -analyzer-display-progress
+ -analyzer-viz-egraph-graphviz
+ ...
+
+The first allows you to specify only analyzing a specific function.
+The second prints to the console what function is being analyzed.  The
+third generates a graphviz dot file of the ExplodedGraph.  This is
+extremely useful when debugging the analyzer and viewing the
+simulation results.
+
+Of course, viewing the CFG (Control-Flow Graph) is also useful:
+
+$ clang -cc1 -help | grep cfg
+ -cfg-add-implicit-dtors Add C++ implicit destructors to CFGs for all analyses
+ -cfg-add-initializers   Add C++ initializers to CFGs for all analyses
+ -cfg-dump               Display Control-Flow Graphs
+ -cfg-view               View Control-Flow Graphs using GraphViz
+ -unoptimized-cfg        Generate unoptimized CFGs for all analyses
+
+-cfg-dump dumps a textual representation of the CFG to the console,
+and -cfg-view creates a GraphViz representation.
+
+= References =
+
+[1] Precise interprocedural dataflow analysis via graph reachability,
+    T Reps, S Horwitz, and M Sagiv, POPL '95,
+    http://portal.acm.org/citation.cfm?id=199462
+
+[2] A memory model for static analysis of C programs, Z Xu, T
+    Kremenek, and J Zhang, http://lcs.ios.ac.cn/~xzx/memmodel.pdf
diff --git a/lib/StaticAnalyzer/RangeConstraintManager.cpp b/lib/StaticAnalyzer/RangeConstraintManager.cpp
new file mode 100644 (file)
index 0000000..c89fa50
--- /dev/null
@@ -0,0 +1,442 @@
+//== RangeConstraintManager.cpp - Manage range constraints.------*- 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 RangeConstraintManager, a class that tracks simple
+//  equality and inequality constraints on symbolic values of GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/ManagerRegistry.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace { class ConstraintRange {}; }
+static int ConstraintRangeIndex = 0;
+
+/// A Range represents the closed range [from, to].  The caller must
+/// guarantee that from <= to.  Note that Range is immutable, so as not
+/// to subvert RangeSet's immutability.
+namespace {
+class Range : public std::pair<const llvm::APSInt*,
+                                                const llvm::APSInt*> {
+public:
+  Range(const llvm::APSInt &from, const llvm::APSInt &to)
+    : std::pair<const llvm::APSInt*, const llvm::APSInt*>(&from, &to) {
+    assert(from <= to);
+  }
+  bool Includes(const llvm::APSInt &v) const {
+    return *first <= v && v <= *second;
+  }
+  const llvm::APSInt &From() const {
+    return *first;
+  }
+  const llvm::APSInt &To() const {
+    return *second;
+  }
+  const llvm::APSInt *getConcreteValue() const {
+    return &From() == &To() ? &From() : NULL;
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddPointer(&From());
+    ID.AddPointer(&To());
+  }
+};
+
+
+class RangeTrait : public llvm::ImutContainerInfo<Range> {
+public:
+  // When comparing if one Range is less than another, we should compare
+  // the actual APSInt values instead of their pointers.  This keeps the order
+  // consistent (instead of comparing by pointer values) and can potentially
+  // be used to speed up some of the operations in RangeSet.
+  static inline bool isLess(key_type_ref lhs, key_type_ref rhs) {
+    return *lhs.first < *rhs.first || (!(*rhs.first < *lhs.first) &&
+                                       *lhs.second < *rhs.second);
+  }
+};
+
+/// RangeSet contains a set of ranges. If the set is empty, then
+///  there the value of a symbol is overly constrained and there are no
+///  possible values for that symbol.
+class RangeSet {
+  typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
+  PrimRangeSet ranges; // no need to make const, since it is an
+                       // ImmutableSet - this allows default operator=
+                       // to work.
+public:
+  typedef PrimRangeSet::Factory Factory;
+  typedef PrimRangeSet::iterator iterator;
+
+  RangeSet(PrimRangeSet RS) : ranges(RS) {}
+
+  iterator begin() const { return ranges.begin(); }
+  iterator end() const { return ranges.end(); }
+
+  bool isEmpty() const { return ranges.isEmpty(); }
+
+  /// Construct a new RangeSet representing '{ [from, to] }'.
+  RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to)
+    : ranges(F.add(F.getEmptySet(), Range(from, to))) {}
+
+  /// Profile - Generates a hash profile of this RangeSet for use
+  ///  by FoldingSet.
+  void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); }
+
+  /// getConcreteValue - If a symbol is contrained to equal a specific integer
+  ///  constant then this method returns that value.  Otherwise, it returns
+  ///  NULL.
+  const llvm::APSInt* getConcreteValue() const {
+    return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0;
+  }
+
+private:
+  void IntersectInRange(BasicValueFactory &BV, Factory &F,
+                        const llvm::APSInt &Lower,
+                        const llvm::APSInt &Upper,
+                        PrimRangeSet &newRanges,
+                        PrimRangeSet::iterator &i,
+                        PrimRangeSet::iterator &e) const {
+    // There are six cases for each range R in the set:
+    //   1. R is entirely before the intersection range.
+    //   2. R is entirely after the intersection range.
+    //   3. R contains the entire intersection range.
+    //   4. R starts before the intersection range and ends in the middle.
+    //   5. R starts in the middle of the intersection range and ends after it.
+    //   6. R is entirely contained in the intersection range.
+    // These correspond to each of the conditions below.
+    for (/* i = begin(), e = end() */; i != e; ++i) {
+      if (i->To() < Lower) {
+        continue;
+      }
+      if (i->From() > Upper) {
+        break;
+      }
+
+      if (i->Includes(Lower)) {
+        if (i->Includes(Upper)) {
+          newRanges = F.add(newRanges, Range(BV.getValue(Lower),
+                                             BV.getValue(Upper)));
+          break;
+        } else
+          newRanges = F.add(newRanges, Range(BV.getValue(Lower), i->To()));
+      } else {
+        if (i->Includes(Upper)) {
+          newRanges = F.add(newRanges, Range(i->From(), BV.getValue(Upper)));
+          break;
+        } else
+          newRanges = F.add(newRanges, *i);
+      }
+    }
+  }
+
+public:
+  // Returns a set containing the values in the receiving set, intersected with
+  // the closed range [Lower, Upper]. Unlike the Range type, this range uses
+  // modular arithmetic, corresponding to the common treatment of C integer
+  // overflow. Thus, if the Lower bound is greater than the Upper bound, the
+  // range is taken to wrap around. This is equivalent to taking the
+  // intersection with the two ranges [Min, Upper] and [Lower, Max],
+  // or, alternatively, /removing/ all integers between Upper and Lower.
+  RangeSet Intersect(BasicValueFactory &BV, Factory &F,
+                     const llvm::APSInt &Lower,
+                     const llvm::APSInt &Upper) const {
+    PrimRangeSet newRanges = F.getEmptySet();
+
+    PrimRangeSet::iterator i = begin(), e = end();
+    if (Lower <= Upper)
+      IntersectInRange(BV, F, Lower, Upper, newRanges, i, e);
+    else {
+      // The order of the next two statements is important!
+      // IntersectInRange() does not reset the iteration state for i and e.
+      // Therefore, the lower range most be handled first.
+      IntersectInRange(BV, F, BV.getMinValue(Upper), Upper, newRanges, i, e);
+      IntersectInRange(BV, F, Lower, BV.getMaxValue(Lower), newRanges, i, e);
+    }
+    return newRanges;
+  }
+
+  void print(llvm::raw_ostream &os) const {
+    bool isFirst = true;
+    os << "{ ";
+    for (iterator i = begin(), e = end(); i != e; ++i) {
+      if (isFirst)
+        isFirst = false;
+      else
+        os << ", ";
+
+      os << '[' << i->From().toString(10) << ", " << i->To().toString(10)
+         << ']';
+    }
+    os << " }";
+  }
+
+  bool operator==(const RangeSet &other) const {
+    return ranges == other.ranges;
+  }
+};
+} // end anonymous namespace
+
+typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy;
+
+namespace clang {
+namespace ento {
+template<>
+struct GRStateTrait<ConstraintRange>
+  : public GRStatePartialTrait<ConstraintRangeTy> {
+  static inline void* GDMIndex() { return &ConstraintRangeIndex; }
+};
+}
+}
+
+namespace {
+class RangeConstraintManager : public SimpleConstraintManager{
+  RangeSet GetRange(const GRState *state, SymbolRef sym);
+public:
+  RangeConstraintManager(SubEngine &subengine)
+    : SimpleConstraintManager(subengine) {}
+
+  const GRState *assumeSymNE(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& Int,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymEQ(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& Int,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymLT(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& Int,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymGT(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& Int,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymGE(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& Int,
+                             const llvm::APSInt& Adjustment);
+
+  const GRState *assumeSymLE(const GRState* state, SymbolRef sym,
+                             const llvm::APSInt& Int,
+                             const llvm::APSInt& Adjustment);
+
+  const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const;
+
+  // FIXME: Refactor into SimpleConstraintManager?
+  bool isEqual(const GRState* St, SymbolRef sym, const llvm::APSInt& V) const {
+    const llvm::APSInt *i = getSymVal(St, sym);
+    return i ? *i == V : false;
+  }
+
+  const GRState* RemoveDeadBindings(const GRState* St, SymbolReaper& SymReaper);
+
+  void print(const GRState* St, llvm::raw_ostream& Out,
+             const char* nl, const char *sep);
+
+private:
+  RangeSet::Factory F;
+};
+
+} // end anonymous namespace
+
+ConstraintManager* ento::CreateRangeConstraintManager(GRStateManager&,
+                                                    SubEngine &subeng) {
+  return new RangeConstraintManager(subeng);
+}
+
+const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
+                                                      SymbolRef sym) const {
+  const ConstraintRangeTy::data_type *T = St->get<ConstraintRange>(sym);
+  return T ? T->getConcreteValue() : NULL;
+}
+
+/// Scan all symbols referenced by the constraints. If the symbol is not alive
+/// as marked in LSymbols, mark it as dead in DSymbols.
+const GRState*
+RangeConstraintManager::RemoveDeadBindings(const GRState* state,
+                                           SymbolReaper& SymReaper) {
+
+  ConstraintRangeTy CR = state->get<ConstraintRange>();
+  ConstraintRangeTy::Factory& CRFactory = state->get_context<ConstraintRange>();
+
+  for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) {
+    SymbolRef sym = I.getKey();
+    if (SymReaper.maybeDead(sym))
+      CR = CRFactory.remove(CR, sym);
+  }
+
+  return state->set<ConstraintRange>(CR);
+}
+
+RangeSet
+RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) {
+  if (ConstraintRangeTy::data_type* V = state->get<ConstraintRange>(sym))
+    return *V;
+
+  // Lazily generate a new RangeSet representing all possible values for the
+  // given symbol type.
+  QualType T = state->getSymbolManager().getType(sym);
+  BasicValueFactory& BV = state->getBasicVals();
+  return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T));
+}
+
+//===------------------------------------------------------------------------===
+// assumeSymX methods: public interface for RangeConstraintManager.
+//===------------------------------------------------------------------------===/
+
+// The syntax for ranges below is mathematical, using [x, y] for closed ranges
+// and (x, y) for open ranges. These ranges are modular, corresponding with
+// a common treatment of C integer overflow. This means that these methods
+// do not have to worry about overflow; RangeSet::Intersect can handle such a
+// "wraparound" range.
+// As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
+// UINT_MAX, 0, 1, and 2.
+
+const GRState*
+RangeConstraintManager::assumeSymNE(const GRState* state, SymbolRef sym,
+                                    const llvm::APSInt& Int,
+                                    const llvm::APSInt& Adjustment) {
+  BasicValueFactory &BV = state->getBasicVals();
+
+  llvm::APSInt Lower = Int-Adjustment;
+  llvm::APSInt Upper = Lower;
+  --Lower;
+  ++Upper;
+
+  // [Int-Adjustment+1, Int-Adjustment-1]
+  // Notice that the lower bound is greater than the upper bound.
+  RangeSet New = GetRange(state, sym).Intersect(BV, F, Upper, Lower);
+  return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
+}
+
+const GRState*
+RangeConstraintManager::assumeSymEQ(const GRState* state, SymbolRef sym,
+                                    const llvm::APSInt& Int,
+                                    const llvm::APSInt& Adjustment) {
+  // [Int-Adjustment, Int-Adjustment]
+  BasicValueFactory &BV = state->getBasicVals();
+  llvm::APSInt AdjInt = Int-Adjustment;
+  RangeSet New = GetRange(state, sym).Intersect(BV, F, AdjInt, AdjInt);
+  return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
+}
+
+const GRState*
+RangeConstraintManager::assumeSymLT(const GRState* state, SymbolRef sym,
+                                    const llvm::APSInt& Int,
+                                    const llvm::APSInt& Adjustment) {
+  BasicValueFactory &BV = state->getBasicVals();
+
+  QualType T = state->getSymbolManager().getType(sym);
+  const llvm::APSInt &Min = BV.getMinValue(T);
+
+  // Special case for Int == Min. This is always false.
+  if (Int == Min)
+    return NULL;
+
+  llvm::APSInt Lower = Min-Adjustment;
+  llvm::APSInt Upper = Int-Adjustment;
+  --Upper;
+
+  RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
+  return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
+}
+
+const GRState*
+RangeConstraintManager::assumeSymGT(const GRState* state, SymbolRef sym,
+                                    const llvm::APSInt& Int,
+                                    const llvm::APSInt& Adjustment) {
+  BasicValueFactory &BV = state->getBasicVals();
+
+  QualType T = state->getSymbolManager().getType(sym);
+  const llvm::APSInt &Max = BV.getMaxValue(T);
+
+  // Special case for Int == Max. This is always false.
+  if (Int == Max)
+    return NULL;
+
+  llvm::APSInt Lower = Int-Adjustment;
+  llvm::APSInt Upper = Max-Adjustment;
+  ++Lower;
+
+  RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
+  return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
+}
+
+const GRState*
+RangeConstraintManager::assumeSymGE(const GRState* state, SymbolRef sym,
+                                    const llvm::APSInt& Int,
+                                    const llvm::APSInt& Adjustment) {
+  BasicValueFactory &BV = state->getBasicVals();
+
+  QualType T = state->getSymbolManager().getType(sym);
+  const llvm::APSInt &Min = BV.getMinValue(T);
+
+  // Special case for Int == Min. This is always feasible.
+  if (Int == Min)
+    return state;
+
+  const llvm::APSInt &Max = BV.getMaxValue(T);
+
+  llvm::APSInt Lower = Int-Adjustment;
+  llvm::APSInt Upper = Max-Adjustment;
+
+  RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
+  return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
+}
+
+const GRState*
+RangeConstraintManager::assumeSymLE(const GRState* state, SymbolRef sym,
+                                    const llvm::APSInt& Int,
+                                    const llvm::APSInt& Adjustment) {
+  BasicValueFactory &BV = state->getBasicVals();
+
+  QualType T = state->getSymbolManager().getType(sym);
+  const llvm::APSInt &Max = BV.getMaxValue(T);
+
+  // Special case for Int == Max. This is always feasible.
+  if (Int == Max)
+    return state;
+
+  const llvm::APSInt &Min = BV.getMinValue(T);
+
+  llvm::APSInt Lower = Min-Adjustment;
+  llvm::APSInt Upper = Int-Adjustment;
+
+  RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
+  return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
+}
+
+//===------------------------------------------------------------------------===
+// Pretty-printing.
+//===------------------------------------------------------------------------===/
+
+void RangeConstraintManager::print(const GRState* St, llvm::raw_ostream& Out,
+                                   const char* nl, const char *sep) {
+
+  ConstraintRangeTy Ranges = St->get<ConstraintRange>();
+
+  if (Ranges.isEmpty())
+    return;
+
+  Out << nl << sep << "ranges of symbol values:";
+
+  for (ConstraintRangeTy::iterator I=Ranges.begin(), E=Ranges.end(); I!=E; ++I){
+    Out << nl << ' ' << I.getKey() << " : ";
+    I.getData().print(Out);
+  }
+}
diff --git a/lib/StaticAnalyzer/RegionStore.cpp b/lib/StaticAnalyzer/RegionStore.cpp
new file mode 100644 (file)
index 0000000..def1b43
--- /dev/null
@@ -0,0 +1,1875 @@
+//== RegionStore.cpp - Field-sensitive store model --------------*- 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 a basic region store model. In this model, we do have field
+// sensitivity. But we assume nothing about the heap shape. So recursive data
+// structures are largely ignored. Basically we do 1-limiting analysis.
+// Parameter pointers are assumed with no aliasing. Pointee objects of
+// parameters are created lazily.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::Optional;
+
+//===----------------------------------------------------------------------===//
+// Representation of binding keys.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class BindingKey {
+public:
+  enum Kind { Direct = 0x0, Default = 0x1 };
+private:
+  llvm ::PointerIntPair<const MemRegion*, 1> P;
+  uint64_t Offset;
+
+  explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
+    : P(r, (unsigned) k), Offset(offset) {}
+public:
+
+  bool isDirect() const { return P.getInt() == Direct; }
+
+  const MemRegion *getRegion() const { return P.getPointer(); }
+  uint64_t getOffset() const { return Offset; }
+
+  void Profile(llvm::FoldingSetNodeID& ID) const {
+    ID.AddPointer(P.getOpaqueValue());
+    ID.AddInteger(Offset);
+  }
+
+  static BindingKey Make(const MemRegion *R, Kind k);
+
+  bool operator<(const BindingKey &X) const {
+    if (P.getOpaqueValue() < X.P.getOpaqueValue())
+      return true;
+    if (P.getOpaqueValue() > X.P.getOpaqueValue())
+      return false;
+    return Offset < X.Offset;
+  }
+
+  bool operator==(const BindingKey &X) const {
+    return P.getOpaqueValue() == X.P.getOpaqueValue() &&
+           Offset == X.Offset;
+  }
+
+  bool isValid() const {
+    return getRegion() != NULL;
+  }
+};
+} // end anonymous namespace
+
+BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
+  if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+    const RegionRawOffset &O = ER->getAsArrayOffset();
+
+    // FIXME: There are some ElementRegions for which we cannot compute
+    // raw offsets yet, including regions with symbolic offsets. These will be
+    // ignored by the store.
+    return BindingKey(O.getRegion(), O.getByteOffset(), k);
+  }
+
+  return BindingKey(R, 0, k);
+}
+
+namespace llvm {
+  static inline
+  llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
+    os << '(' << K.getRegion() << ',' << K.getOffset()
+       << ',' << (K.isDirect() ? "direct" : "default")
+       << ')';
+    return os;
+  }
+} // end llvm namespace
+
+//===----------------------------------------------------------------------===//
+// Actual Store type.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<BindingKey, SVal> RegionBindings;
+
+//===----------------------------------------------------------------------===//
+// Fine-grained control of RegionStoreManager.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct minimal_features_tag {};
+struct maximal_features_tag {};
+
+class RegionStoreFeatures {
+  bool SupportsFields;
+public:
+  RegionStoreFeatures(minimal_features_tag) :
+    SupportsFields(false) {}
+
+  RegionStoreFeatures(maximal_features_tag) :
+    SupportsFields(true) {}
+
+  void enableFields(bool t) { SupportsFields = t; }
+
+  bool supportsFields() const { return SupportsFields; }
+};
+}
+
+//===----------------------------------------------------------------------===//
+// Main RegionStore logic.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class RegionStoreSubRegionMap : public SubRegionMap {
+public:
+  typedef llvm::ImmutableSet<const MemRegion*> Set;
+  typedef llvm::DenseMap<const MemRegion*, Set> Map;
+private:
+  Set::Factory F;
+  Map M;
+public:
+  bool add(const MemRegion* Parent, const MemRegion* SubRegion) {
+    Map::iterator I = M.find(Parent);
+
+    if (I == M.end()) {
+      M.insert(std::make_pair(Parent, F.add(F.getEmptySet(), SubRegion)));
+      return true;
+    }
+
+    I->second = F.add(I->second, SubRegion);
+    return false;
+  }
+
+  void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
+
+  ~RegionStoreSubRegionMap() {}
+
+  const Set *getSubRegions(const MemRegion *Parent) const {
+    Map::const_iterator I = M.find(Parent);
+    return I == M.end() ? NULL : &I->second;
+  }
+
+  bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
+    Map::const_iterator I = M.find(Parent);
+
+    if (I == M.end())
+      return true;
+
+    Set S = I->second;
+    for (Set::iterator SI=S.begin(),SE=S.end(); SI != SE; ++SI) {
+      if (!V.Visit(Parent, *SI))
+        return false;
+    }
+
+    return true;
+  }
+};
+
+void
+RegionStoreSubRegionMap::process(llvm::SmallVectorImpl<const SubRegion*> &WL,
+                                 const SubRegion *R) {
+  const MemRegion *superR = R->getSuperRegion();
+  if (add(superR, R))
+    if (const SubRegion *sr = dyn_cast<SubRegion>(superR))
+      WL.push_back(sr);
+}
+
+class RegionStoreManager : public StoreManager {
+  const RegionStoreFeatures Features;
+  RegionBindings::Factory RBFactory;
+
+public:
+  RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
+    : StoreManager(mgr),
+      Features(f),
+      RBFactory(mgr.getAllocator()) {}
+
+  SubRegionMap *getSubRegionMap(Store store) {
+    return getRegionStoreSubRegionMap(store);
+  }
+
+  RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store);
+
+  Optional<SVal> getDirectBinding(RegionBindings B, const MemRegion *R);
+  /// getDefaultBinding - Returns an SVal* representing an optional default
+  ///  binding associated with a region and its subregions.
+  Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
+
+  /// setImplicitDefaultValue - Set the default binding for the provided
+  ///  MemRegion to the value implicitly defined for compound literals when
+  ///  the value is not specified.
+  Store setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
+
+  /// ArrayToPointer - Emulates the "decay" of an array to a pointer
+  ///  type.  'Array' represents the lvalue of the array being decayed
+  ///  to a pointer, and the returned SVal represents the decayed
+  ///  version of that lvalue (i.e., a pointer to the first element of
+  ///  the array).  This is called by ExprEngine when evaluating
+  ///  casts from arrays to pointers.
+  SVal ArrayToPointer(Loc Array);
+
+  /// For DerivedToBase casts, create a CXXBaseObjectRegion and return it.
+  virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType);
+
+  SVal evalBinOp(BinaryOperator::Opcode Op,Loc L, NonLoc R, QualType resultTy);
+
+  Store getInitialStore(const LocationContext *InitLoc) {
+    return RBFactory.getEmptyMap().getRoot();
+  }
+
+  //===-------------------------------------------------------------------===//
+  // Binding values to regions.
+  //===-------------------------------------------------------------------===//
+
+  Store InvalidateRegions(Store store,
+                          const MemRegion * const *Begin,
+                          const MemRegion * const *End,
+                          const Expr *E, unsigned Count,
+                          InvalidatedSymbols *IS,
+                          bool invalidateGlobals,
+                          InvalidatedRegions *Regions);
+
+public:   // Made public for helper classes.
+
+  void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
+                               RegionStoreSubRegionMap &M);
+
+  RegionBindings addBinding(RegionBindings B, BindingKey K, SVal V);
+
+  RegionBindings addBinding(RegionBindings B, const MemRegion *R,
+                     BindingKey::Kind k, SVal V);
+
+  const SVal *lookup(RegionBindings B, BindingKey K);
+  const SVal *lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
+
+  RegionBindings removeBinding(RegionBindings B, BindingKey K);
+  RegionBindings removeBinding(RegionBindings B, const MemRegion *R,
+                        BindingKey::Kind k);
+
+  RegionBindings removeBinding(RegionBindings B, const MemRegion *R) {
+    return removeBinding(removeBinding(B, R, BindingKey::Direct), R,
+                        BindingKey::Default);
+  }
+
+public: // Part of public interface to class.
+
+  Store Bind(Store store, Loc LV, SVal V);
+
+  // BindDefault is only used to initialize a region with a default value.
+  Store BindDefault(Store store, const MemRegion *R, SVal V) {
+    RegionBindings B = GetRegionBindings(store);
+    assert(!lookup(B, R, BindingKey::Default));
+    assert(!lookup(B, R, BindingKey::Direct));
+    return addBinding(B, R, BindingKey::Default, V).getRoot();
+  }
+
+  Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
+                            const LocationContext *LC, SVal V);
+
+  Store BindDecl(Store store, const VarRegion *VR, SVal InitVal);
+
+  Store BindDeclWithNoInit(Store store, const VarRegion *) {
+    return store;
+  }
+
+  /// BindStruct - Bind a compound value to a structure.
+  Store BindStruct(Store store, const TypedRegion* R, SVal V);
+
+  Store BindArray(Store store, const TypedRegion* R, SVal V);
+
+  /// KillStruct - Set the entire struct to unknown.
+  Store KillStruct(Store store, const TypedRegion* R, SVal DefaultVal);
+
+  Store Remove(Store store, Loc LV);
+
+
+  //===------------------------------------------------------------------===//
+  // Loading values from regions.
+  //===------------------------------------------------------------------===//
+
+  /// The high level logic for this method is this:
+  /// Retrieve (L)
+  ///   if L has binding
+  ///     return L's binding
+  ///   else if L is in killset
+  ///     return unknown
+  ///   else
+  ///     if L is on stack or heap
+  ///       return undefined
+  ///     else
+  ///       return symbolic
+  SVal Retrieve(Store store, Loc L, QualType T = QualType());
+
+  SVal RetrieveElement(Store store, const ElementRegion *R);
+
+  SVal RetrieveField(Store store, const FieldRegion *R);
+
+  SVal RetrieveObjCIvar(Store store, const ObjCIvarRegion *R);
+
+  SVal RetrieveVar(Store store, const VarRegion *R);
+
+  SVal RetrieveLazySymbol(const TypedRegion *R);
+
+  SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R,
+                                    QualType Ty, const MemRegion *superR);
+
+  /// Retrieve the values in a struct and return a CompoundVal, used when doing
+  /// struct copy:
+  /// struct s x, y;
+  /// x = y;
+  /// y's value is retrieved by this method.
+  SVal RetrieveStruct(Store store, const TypedRegion* R);
+
+  SVal RetrieveArray(Store store, const TypedRegion* R);
+
+  /// Used to lazily generate derived symbols for bindings that are defined
+  ///  implicitly by default bindings in a super region.
+  Optional<SVal> RetrieveDerivedDefaultValue(RegionBindings B,
+                                             const MemRegion *superR,
+                                             const TypedRegion *R, QualType Ty);
+
+  /// Get the state and region whose binding this region R corresponds to.
+  std::pair<Store, const MemRegion*>
+  GetLazyBinding(RegionBindings B, const MemRegion *R);
+
+  Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
+                         const TypedRegion *R);
+
+  //===------------------------------------------------------------------===//
+  // State pruning.
+  //===------------------------------------------------------------------===//
+
+  /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
+  ///  It returns a new Store with these values removed.
+  Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx,
+                           SymbolReaper& SymReaper,
+                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+
+  Store EnterStackFrame(const GRState *state, const StackFrameContext *frame);
+
+  //===------------------------------------------------------------------===//
+  // Region "extents".
+  //===------------------------------------------------------------------===//
+
+  // FIXME: This method will soon be eliminated; see the note in Store.h.
+  DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+                                         const MemRegion* R, QualType EleTy);
+
+  //===------------------------------------------------------------------===//
+  // Utility methods.
+  //===------------------------------------------------------------------===//
+
+  static inline RegionBindings GetRegionBindings(Store store) {
+    return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+  }
+
+  void print(Store store, llvm::raw_ostream& Out, const char* nl,
+             const char *sep);
+
+  void iterBindings(Store store, BindingsHandler& f) {
+    RegionBindings B = GetRegionBindings(store);
+    for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+      const BindingKey &K = I.getKey();
+      if (!K.isDirect())
+        continue;
+      if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion())) {
+        // FIXME: Possibly incorporate the offset?
+        if (!f.HandleBinding(*this, store, R, I.getData()))
+          return;
+      }
+    }
+  }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RegionStore creation.
+//===----------------------------------------------------------------------===//
+
+StoreManager *ento::CreateRegionStoreManager(GRStateManager& StMgr) {
+  RegionStoreFeatures F = maximal_features_tag();
+  return new RegionStoreManager(StMgr, F);
+}
+
+StoreManager *ento::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) {
+  RegionStoreFeatures F = minimal_features_tag();
+  F.enableFields(true);
+  return new RegionStoreManager(StMgr, F);
+}
+
+
+RegionStoreSubRegionMap*
+RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
+  RegionBindings B = GetRegionBindings(store);
+  RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap();
+
+  llvm::SmallVector<const SubRegion*, 10> WL;
+
+  for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
+    if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
+      M->process(WL, R);
+
+  // We also need to record in the subregion map "intermediate" regions that
+  // don't have direct bindings but are super regions of those that do.
+  while (!WL.empty()) {
+    const SubRegion *R = WL.back();
+    WL.pop_back();
+    M->process(WL, R);
+  }
+
+  return M;
+}
+
+//===----------------------------------------------------------------------===//
+// Region Cluster analysis.
+//===----------------------------------------------------------------------===//
+
+namespace {
+template <typename DERIVED>
+class ClusterAnalysis  {
+protected:
+  typedef BumpVector<BindingKey> RegionCluster;
+  typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap;
+  llvm::DenseMap<const RegionCluster*, unsigned> Visited;
+  typedef llvm::SmallVector<std::pair<const MemRegion *, RegionCluster*>, 10>
+    WorkList;
+
+  BumpVectorContext BVC;
+  ClusterMap ClusterM;
+  WorkList WL;
+
+  RegionStoreManager &RM;
+  ASTContext &Ctx;
+  SValBuilder &svalBuilder;
+
+  RegionBindings B;
+  
+  const bool includeGlobals;
+
+public:
+  ClusterAnalysis(RegionStoreManager &rm, GRStateManager &StateMgr,
+                  RegionBindings b, const bool includeGlobals)
+    : RM(rm), Ctx(StateMgr.getContext()),
+      svalBuilder(StateMgr.getSValBuilder()),
+      B(b), includeGlobals(includeGlobals) {}
+
+  RegionBindings getRegionBindings() const { return B; }
+
+  RegionCluster &AddToCluster(BindingKey K) {
+    const MemRegion *R = K.getRegion();
+    const MemRegion *baseR = R->getBaseRegion();
+    RegionCluster &C = getCluster(baseR);
+    C.push_back(K, BVC);
+    static_cast<DERIVED*>(this)->VisitAddedToCluster(baseR, C);
+    return C;
+  }
+
+  bool isVisited(const MemRegion *R) {
+    return (bool) Visited[&getCluster(R->getBaseRegion())];
+  }
+
+  RegionCluster& getCluster(const MemRegion *R) {
+    RegionCluster *&CRef = ClusterM[R];
+    if (!CRef) {
+      void *Mem = BVC.getAllocator().template Allocate<RegionCluster>();
+      CRef = new (Mem) RegionCluster(BVC, 10);
+    }
+    return *CRef;
+  }
+
+  void GenerateClusters() {
+      // Scan the entire set of bindings and make the region clusters.
+    for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+      RegionCluster &C = AddToCluster(RI.getKey());
+      if (const MemRegion *R = RI.getData().getAsRegion()) {
+        // Generate a cluster, but don't add the region to the cluster
+        // if there aren't any bindings.
+        getCluster(R->getBaseRegion());
+      }
+      if (includeGlobals) {
+        const MemRegion *R = RI.getKey().getRegion();
+        if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()))
+          AddToWorkList(R, C);
+      }
+    }
+  }
+
+  bool AddToWorkList(const MemRegion *R, RegionCluster &C) {
+    if (unsigned &visited = Visited[&C])
+      return false;
+    else
+      visited = 1;
+
+    WL.push_back(std::make_pair(R, &C));
+    return true;
+  }
+
+  bool AddToWorkList(BindingKey K) {
+    return AddToWorkList(K.getRegion());
+  }
+
+  bool AddToWorkList(const MemRegion *R) {
+    const MemRegion *baseR = R->getBaseRegion();
+    return AddToWorkList(baseR, getCluster(baseR));
+  }
+
+  void RunWorkList() {
+    while (!WL.empty()) {
+      const MemRegion *baseR;
+      RegionCluster *C;
+      llvm::tie(baseR, C) = WL.back();
+      WL.pop_back();
+
+        // First visit the cluster.
+      static_cast<DERIVED*>(this)->VisitCluster(baseR, C->begin(), C->end());
+
+        // Next, visit the base region.
+      static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
+    }
+  }
+
+public:
+  void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C) {}
+  void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) {}
+  void VisitBaseRegion(const MemRegion *baseR) {}
+};
+}
+
+//===----------------------------------------------------------------------===//
+// Binding invalidation.
+//===----------------------------------------------------------------------===//
+
+void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
+                                                 const MemRegion *R,
+                                                 RegionStoreSubRegionMap &M) {
+
+  if (const RegionStoreSubRegionMap::Set *S = M.getSubRegions(R))
+    for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end();
+         I != E; ++I)
+      RemoveSubRegionBindings(B, *I, M);
+
+  B = removeBinding(B, R);
+}
+
+namespace {
+class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker>
+{
+  const Expr *Ex;
+  unsigned Count;
+  StoreManager::InvalidatedSymbols *IS;
+  StoreManager::InvalidatedRegions *Regions;
+public:
+  InvalidateRegionsWorker(RegionStoreManager &rm,
+                          GRStateManager &stateMgr,
+                          RegionBindings b,
+                          const Expr *ex, unsigned count,
+                          StoreManager::InvalidatedSymbols *is,
+                          StoreManager::InvalidatedRegions *r,
+                          bool includeGlobals)
+    : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
+      Ex(ex), Count(count), IS(is), Regions(r) {}
+
+  void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
+  void VisitBaseRegion(const MemRegion *baseR);
+
+private:
+  void VisitBinding(SVal V);
+};
+}
+
+void InvalidateRegionsWorker::VisitBinding(SVal V) {
+  // A symbol?  Mark it touched by the invalidation.
+  if (IS)
+    if (SymbolRef Sym = V.getAsSymbol())
+      IS->insert(Sym);
+
+  if (const MemRegion *R = V.getAsRegion()) {
+    AddToWorkList(R);
+    return;
+  }
+
+  // Is it a LazyCompoundVal?  All references get invalidated as well.
+  if (const nonloc::LazyCompoundVal *LCS =
+        dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+    const MemRegion *LazyR = LCS->getRegion();
+    RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+
+    for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+      const SubRegion *baseR = dyn_cast<SubRegion>(RI.getKey().getRegion());
+      if (baseR && baseR->isSubRegionOf(LazyR))
+        VisitBinding(RI.getData());
+    }
+
+    return;
+  }
+}
+
+void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
+                                           BindingKey *I, BindingKey *E) {
+  for ( ; I != E; ++I) {
+    // Get the old binding.  Is it a region?  If so, add it to the worklist.
+    const BindingKey &K = *I;
+    if (const SVal *V = RM.lookup(B, K))
+      VisitBinding(*V);
+
+    B = RM.removeBinding(B, K);
+  }
+}
+
+void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
+  if (IS) {
+    // Symbolic region?  Mark that symbol touched by the invalidation.
+    if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+      IS->insert(SR->getSymbol());
+  }
+
+  // BlockDataRegion?  If so, invalidate captured variables that are passed
+  // by reference.
+  if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
+    for (BlockDataRegion::referenced_vars_iterator
+         BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
+         BI != BE; ++BI) {
+      const VarRegion *VR = *BI;
+      const VarDecl *VD = VR->getDecl();
+      if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+        AddToWorkList(VR);
+    }
+    return;
+  }
+
+  // Otherwise, we have a normal data region. Record that we touched the region.
+  if (Regions)
+    Regions->push_back(baseR);
+
+  if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
+    // Invalidate the region by setting its default value to
+    // conjured symbol. The type of the symbol is irrelavant.
+    DefinedOrUnknownSVal V =
+      svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count);
+    B = RM.addBinding(B, baseR, BindingKey::Default, V);
+    return;
+  }
+
+  if (!baseR->isBoundable())
+    return;
+
+  const TypedRegion *TR = cast<TypedRegion>(baseR);
+  QualType T = TR->getValueType();
+
+    // Invalidate the binding.
+  if (T->isStructureType()) {
+    // Invalidate the region by setting its default value to
+    // conjured symbol. The type of the symbol is irrelavant.
+    DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy,
+                                                         Count);
+    B = RM.addBinding(B, baseR, BindingKey::Default, V);
+    return;
+  }
+
+  if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
+      // Set the default value of the array to conjured symbol.
+    DefinedOrUnknownSVal V =
+    svalBuilder.getConjuredSymbolVal(baseR, Ex, AT->getElementType(), Count);
+    B = RM.addBinding(B, baseR, BindingKey::Default, V);
+    return;
+  }
+  
+  if (includeGlobals && 
+      isa<NonStaticGlobalSpaceRegion>(baseR->getMemorySpace())) {
+    // If the region is a global and we are invalidating all globals,
+    // just erase the entry.  This causes all globals to be lazily
+    // symbolicated from the same base symbol.
+    B = RM.removeBinding(B, baseR);
+    return;
+  }
+  
+
+  DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, T, Count);
+  assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
+  B = RM.addBinding(B, baseR, BindingKey::Direct, V);
+}
+
+Store RegionStoreManager::InvalidateRegions(Store store,
+                                            const MemRegion * const *I,
+                                            const MemRegion * const *E,
+                                            const Expr *Ex, unsigned Count,
+                                            InvalidatedSymbols *IS,
+                                            bool invalidateGlobals,
+                                            InvalidatedRegions *Regions) {
+  InvalidateRegionsWorker W(*this, StateMgr,
+                            RegionStoreManager::GetRegionBindings(store),
+                            Ex, Count, IS, Regions, invalidateGlobals);
+
+  // Scan the bindings and generate the clusters.
+  W.GenerateClusters();
+
+  // Add I .. E to the worklist.
+  for ( ; I != E; ++I)
+    W.AddToWorkList(*I);
+
+  W.RunWorkList();
+
+  // Return the new bindings.
+  RegionBindings B = W.getRegionBindings();
+
+  if (invalidateGlobals) {
+    // Bind the non-static globals memory space to a new symbol that we will
+    // use to derive the bindings for all non-static globals.
+    const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion();
+    SVal V =
+      svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex,
+                                  /* symbol type, doesn't matter */ Ctx.IntTy,
+                                  Count);
+    B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
+
+    // Even if there are no bindings in the global scope, we still need to
+    // record that we touched it.
+    if (Regions)
+      Regions->push_back(GS);
+  }
+
+  return B.getRoot();
+}
+
+//===----------------------------------------------------------------------===//
+// Extents for regions.
+//===----------------------------------------------------------------------===//
+
+DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
+                                                           const MemRegion *R,
+                                                           QualType EleTy) {
+  SVal Size = cast<SubRegion>(R)->getExtent(svalBuilder);
+  const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size);
+  if (!SizeInt)
+    return UnknownVal();
+
+  CharUnits RegionSize = CharUnits::fromQuantity(SizeInt->getSExtValue());
+
+  if (Ctx.getAsVariableArrayType(EleTy)) {
+    // FIXME: We need to track extra state to properly record the size
+    // of VLAs.  Returning UnknownVal here, however, is a stop-gap so that
+    // we don't have a divide-by-zero below.
+    return UnknownVal();
+  }
+
+  CharUnits EleSize = Ctx.getTypeSizeInChars(EleTy);
+
+  // If a variable is reinterpreted as a type that doesn't fit into a larger
+  // type evenly, round it down.
+  // This is a signed value, since it's used in arithmetic with signed indices.
+  return svalBuilder.makeIntVal(RegionSize / EleSize, false);
+}
+
+//===----------------------------------------------------------------------===//
+// Location and region casting.
+//===----------------------------------------------------------------------===//
+
+/// ArrayToPointer - Emulates the "decay" of an array to a pointer
+///  type.  'Array' represents the lvalue of the array being decayed
+///  to a pointer, and the returned SVal represents the decayed
+///  version of that lvalue (i.e., a pointer to the first element of
+///  the array).  This is called by ExprEngine when evaluating casts
+///  from arrays to pointers.
+SVal RegionStoreManager::ArrayToPointer(Loc Array) {
+  if (!isa<loc::MemRegionVal>(Array))
+    return UnknownVal();
+
+  const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion();
+  const TypedRegion* ArrayR = dyn_cast<TypedRegion>(R);
+
+  if (!ArrayR)
+    return UnknownVal();
+
+  // Strip off typedefs from the ArrayRegion's ValueType.
+  QualType T = ArrayR->getValueType().getDesugaredType(Ctx);
+  ArrayType *AT = cast<ArrayType>(T);
+  T = AT->getElementType();
+
+  NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
+  return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx));
+}
+
+SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) {
+  const CXXRecordDecl *baseDecl;
+  if (baseType->isPointerType())
+    baseDecl = baseType->getCXXRecordDeclForPointerType();
+  else
+    baseDecl = baseType->getAsCXXRecordDecl();
+
+  assert(baseDecl && "not a CXXRecordDecl?");
+
+  loc::MemRegionVal *derivedRegVal = dyn_cast<loc::MemRegionVal>(&derived);
+  if (!derivedRegVal)
+    return derived;
+
+  const MemRegion *baseReg = 
+    MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion());
+  return loc::MemRegionVal(baseReg);
+}
+//===----------------------------------------------------------------------===//
+// Pointer arithmetic.
+//===----------------------------------------------------------------------===//
+
+SVal RegionStoreManager::evalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
+                                   QualType resultTy) {
+  // Assume the base location is MemRegionVal.
+  if (!isa<loc::MemRegionVal>(L))
+    return UnknownVal();
+
+  // Special case for zero RHS.
+  if (R.isZeroConstant()) {
+    switch (Op) {
+    default:
+      // Handle it normally.
+      break;
+    case BO_Add:
+    case BO_Sub:
+      // FIXME: does this need to be casted to match resultTy?
+      return L;
+    }
+  }
+
+  const MemRegion* MR = cast<loc::MemRegionVal>(L).getRegion();
+  const ElementRegion *ER = 0;
+
+  switch (MR->getKind()) {
+    case MemRegion::SymbolicRegionKind: {
+      const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
+      SymbolRef Sym = SR->getSymbol();
+      QualType T = Sym->getType(Ctx);
+      QualType EleTy;
+
+      if (const PointerType *PT = T->getAs<PointerType>())
+        EleTy = PT->getPointeeType();
+      else
+        EleTy = T->getAs<ObjCObjectPointerType>()->getPointeeType();
+
+      const NonLoc &ZeroIdx = svalBuilder.makeZeroArrayIndex();
+      ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, Ctx);
+      break;
+    }
+    case MemRegion::AllocaRegionKind: {
+      const AllocaRegion *AR = cast<AllocaRegion>(MR);
+      QualType EleTy = Ctx.CharTy; // Create an ElementRegion of bytes.
+      NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
+      ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, Ctx);
+      break;
+    }
+
+    case MemRegion::ElementRegionKind: {
+      ER = cast<ElementRegion>(MR);
+      break;
+    }
+
+    // Not yet handled.
+    case MemRegion::VarRegionKind:
+    case MemRegion::StringRegionKind: {
+
+    }
+    // Fall-through.
+    case MemRegion::CompoundLiteralRegionKind:
+    case MemRegion::FieldRegionKind:
+    case MemRegion::ObjCIvarRegionKind:
+    case MemRegion::CXXTempObjectRegionKind:
+    case MemRegion::CXXBaseObjectRegionKind:
+      return UnknownVal();
+
+    case MemRegion::FunctionTextRegionKind:
+    case MemRegion::BlockTextRegionKind:
+    case MemRegion::BlockDataRegionKind:
+      // Technically this can happen if people do funny things with casts.
+      return UnknownVal();
+
+    case MemRegion::CXXThisRegionKind:
+      assert(0 &&
+             "Cannot perform pointer arithmetic on implicit argument 'this'");
+    case MemRegion::GenericMemSpaceRegionKind:
+    case MemRegion::StackLocalsSpaceRegionKind:
+    case MemRegion::StackArgumentsSpaceRegionKind:
+    case MemRegion::HeapSpaceRegionKind:
+    case MemRegion::NonStaticGlobalSpaceRegionKind:
+    case MemRegion::StaticGlobalSpaceRegionKind:
+    case MemRegion::UnknownSpaceRegionKind:
+      assert(0 && "Cannot perform pointer arithmetic on a MemSpace");
+      return UnknownVal();
+  }
+
+  SVal Idx = ER->getIndex();
+  nonloc::ConcreteInt* Base = dyn_cast<nonloc::ConcreteInt>(&Idx);
+
+  // For now, only support:
+  //  (a) concrete integer indices that can easily be resolved
+  //  (b) 0 + symbolic index
+  if (Base) {
+    if (nonloc::ConcreteInt *Offset = dyn_cast<nonloc::ConcreteInt>(&R)) {
+      // FIXME: Should use SValBuilder here.
+      SVal NewIdx =
+        Base->evalBinOp(svalBuilder, Op,
+                cast<nonloc::ConcreteInt>(svalBuilder.convertToArrayIndex(*Offset)));
+
+      if (!isa<NonLoc>(NewIdx))
+        return UnknownVal();
+
+      const MemRegion* NewER =
+        MRMgr.getElementRegion(ER->getElementType(), cast<NonLoc>(NewIdx),
+                               ER->getSuperRegion(), Ctx);
+      return svalBuilder.makeLoc(NewER);
+    }
+    if (0 == Base->getValue()) {
+      const MemRegion* NewER =
+        MRMgr.getElementRegion(ER->getElementType(), R,
+                               ER->getSuperRegion(), Ctx);
+      return svalBuilder.makeLoc(NewER);
+    }
+  }
+
+  return UnknownVal();
+}
+
+//===----------------------------------------------------------------------===//
+// Loading values from regions.
+//===----------------------------------------------------------------------===//
+
+Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
+                                                    const MemRegion *R) {
+
+  if (const SVal *V = lookup(B, R, BindingKey::Direct))
+    return *V;
+
+  return Optional<SVal>();
+}
+
+Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
+                                                     const MemRegion *R) {
+  if (R->isBoundable())
+    if (const TypedRegion *TR = dyn_cast<TypedRegion>(R))
+      if (TR->getValueType()->isUnionType())
+        return UnknownVal();
+
+  if (const SVal *V = lookup(B, R, BindingKey::Default))
+    return *V;
+
+  return Optional<SVal>();
+}
+
+SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
+  assert(!isa<UnknownVal>(L) && "location unknown");
+  assert(!isa<UndefinedVal>(L) && "location undefined");
+
+  // For access to concrete addresses, return UnknownVal.  Checks
+  // for null dereferences (and similar errors) are done by checkers, not
+  // the Store.
+  // FIXME: We can consider lazily symbolicating such memory, but we really
+  // should defer this when we can reason easily about symbolicating arrays
+  // of bytes.
+  if (isa<loc::ConcreteInt>(L)) {
+    return UnknownVal();
+  }
+
+  const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
+
+  if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR)) {
+    if (T.isNull()) {
+      const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
+      T = SR->getSymbol()->getType(Ctx);
+    }
+    MR = GetElementZeroRegion(MR, T);
+  }
+
+  if (isa<CodeTextRegion>(MR)) {
+    assert(0 && "Why load from a code text region?");
+    return UnknownVal();
+  }
+
+  // FIXME: Perhaps this method should just take a 'const MemRegion*' argument
+  //  instead of 'Loc', and have the other Loc cases handled at a higher level.
+  const TypedRegion *R = cast<TypedRegion>(MR);
+  QualType RTy = R->getValueType();
+
+  // FIXME: We should eventually handle funny addressing.  e.g.:
+  //
+  //   int x = ...;
+  //   int *p = &x;
+  //   char *q = (char*) p;
+  //   char c = *q;  // returns the first byte of 'x'.
+  //
+  // Such funny addressing will occur due to layering of regions.
+
+  if (RTy->isStructureOrClassType())
+    return RetrieveStruct(store, R);
+
+  // FIXME: Handle unions.
+  if (RTy->isUnionType())
+    return UnknownVal();
+
+  if (RTy->isArrayType())
+    return RetrieveArray(store, R);
+
+  // FIXME: handle Vector types.
+  if (RTy->isVectorType())
+    return UnknownVal();
+
+  if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
+    return CastRetrievedVal(RetrieveField(store, FR), FR, T, false);
+
+  if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
+    // FIXME: Here we actually perform an implicit conversion from the loaded
+    // value to the element type.  Eventually we want to compose these values
+    // more intelligently.  For example, an 'element' can encompass multiple
+    // bound regions (e.g., several bound bytes), or could be a subset of
+    // a larger value.
+    return CastRetrievedVal(RetrieveElement(store, ER), ER, T, false);
+  }
+
+  if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
+    // FIXME: Here we actually perform an implicit conversion from the loaded
+    // value to the ivar type.  What we should model is stores to ivars
+    // that blow past the extent of the ivar.  If the address of the ivar is
+    // reinterpretted, it is possible we stored a different value that could
+    // fit within the ivar.  Either we need to cast these when storing them
+    // or reinterpret them lazily (as we do here).
+    return CastRetrievedVal(RetrieveObjCIvar(store, IVR), IVR, T, false);
+  }
+
+  if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+    // FIXME: Here we actually perform an implicit conversion from the loaded
+    // value to the variable type.  What we should model is stores to variables
+    // that blow past the extent of the variable.  If the address of the
+    // variable is reinterpretted, it is possible we stored a different value
+    // that could fit within the variable.  Either we need to cast these when
+    // storing them or reinterpret them lazily (as we do here).
+    return CastRetrievedVal(RetrieveVar(store, VR), VR, T, false);
+  }
+
+  RegionBindings B = GetRegionBindings(store);
+  const SVal *V = lookup(B, R, BindingKey::Direct);
+
+  // Check if the region has a binding.
+  if (V)
+    return *V;
+
+  // The location does not have a bound value.  This means that it has
+  // the value it had upon its creation and/or entry to the analyzed
+  // function/method.  These are either symbolic values or 'undefined'.
+  if (R->hasStackNonParametersStorage()) {
+    // All stack variables are considered to have undefined values
+    // upon creation.  All heap allocated blocks are considered to
+    // have undefined values as well unless they are explicitly bound
+    // to specific values.
+    return UndefinedVal();
+  }
+
+  // All other values are symbolic.
+  return svalBuilder.getRegionValueSymbolVal(R);
+}
+
+std::pair<Store, const MemRegion *>
+RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
+  if (Optional<SVal> OV = getDirectBinding(B, R))
+    if (const nonloc::LazyCompoundVal *V =
+        dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
+      return std::make_pair(V->getStore(), V->getRegion());
+
+  if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+    const std::pair<Store, const MemRegion *> &X =
+      GetLazyBinding(B, ER->getSuperRegion());
+
+    if (X.second)
+      return std::make_pair(X.first,
+                            MRMgr.getElementRegionWithSuper(ER, X.second));
+  }
+  else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+    const std::pair<Store, const MemRegion *> &X =
+      GetLazyBinding(B, FR->getSuperRegion());
+
+    if (X.second)
+      return std::make_pair(X.first,
+                            MRMgr.getFieldRegionWithSuper(FR, X.second));
+  }
+  // The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
+  // possible for a valid lazy binding.
+  return std::make_pair((Store) 0, (const MemRegion *) 0);
+}
+
+SVal RegionStoreManager::RetrieveElement(Store store,
+                                         const ElementRegion* R) {
+  // Check if the region has a binding.
+  RegionBindings B = GetRegionBindings(store);
+  if (const Optional<SVal> &V = getDirectBinding(B, R))
+    return *V;
+
+  const MemRegion* superR = R->getSuperRegion();
+
+  // Check if the region is an element region of a string literal.
+  if (const StringRegion *StrR=dyn_cast<StringRegion>(superR)) {
+    // FIXME: Handle loads from strings where the literal is treated as
+    // an integer, e.g., *((unsigned int*)"hello")
+    QualType T = Ctx.getAsArrayType(StrR->getValueType())->getElementType();
+    if (T != Ctx.getCanonicalType(R->getElementType()))
+      return UnknownVal();
+
+    const StringLiteral *Str = StrR->getStringLiteral();
+    SVal Idx = R->getIndex();
+    if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
+      int64_t i = CI->getValue().getSExtValue();
+      int64_t byteLength = Str->getByteLength();
+      // Technically, only i == byteLength is guaranteed to be null.
+      // However, such overflows should be caught before reaching this point;
+      // the only time such an access would be made is if a string literal was
+      // used to initialize a larger array.
+      char c = (i >= byteLength) ? '\0' : Str->getString()[i];
+      return svalBuilder.makeIntVal(c, T);
+    }
+  }
+  
+  // Check for loads from a code text region.  For such loads, just give up.
+  if (isa<CodeTextRegion>(superR))
+    return UnknownVal();
+
+  // Handle the case where we are indexing into a larger scalar object.
+  // For example, this handles:
+  //   int x = ...
+  //   char *y = &x;
+  //   return *y;
+  // FIXME: This is a hack, and doesn't do anything really intelligent yet.
+  const RegionRawOffset &O = R->getAsArrayOffset();
+  if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) {
+    QualType baseT = baseR->getValueType();
+    if (baseT->isScalarType()) {
+      QualType elemT = R->getElementType();
+      if (elemT->isScalarType()) {
+        if (Ctx.getTypeSizeInChars(baseT) >= Ctx.getTypeSizeInChars(elemT)) {
+          if (const Optional<SVal> &V = getDirectBinding(B, superR)) {
+            if (SymbolRef parentSym = V->getAsSymbol())
+              return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
+
+            if (V->isUnknownOrUndef())
+              return *V;
+            // Other cases: give up.  We are indexing into a larger object
+            // that has some value, but we don't know how to handle that yet.
+            return UnknownVal();
+          }
+        }
+      }
+    }
+  }
+  return RetrieveFieldOrElementCommon(store, R, R->getElementType(), superR);
+}
+
+SVal RegionStoreManager::RetrieveField(Store store,
+                                       const FieldRegion* R) {
+
+  // Check if the region has a binding.
+  RegionBindings B = GetRegionBindings(store);
+  if (const Optional<SVal> &V = getDirectBinding(B, R))
+    return *V;
+
+  QualType Ty = R->getValueType();
+  return RetrieveFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
+}
+
+Optional<SVal>
+RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B,
+                                                const MemRegion *superR,
+                                                const TypedRegion *R,
+                                                QualType Ty) {
+
+  if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
+    if (SymbolRef parentSym = D->getAsSymbol())
+      return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
+
+    if (D->isZeroConstant())
+      return svalBuilder.makeZeroVal(Ty);
+
+    if (D->isUnknownOrUndef())
+      return *D;
+
+    assert(0 && "Unknown default value");
+  }
+
+  return Optional<SVal>();
+}
+
+SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store,
+                                                      const TypedRegion *R,
+                                                      QualType Ty,
+                                                      const MemRegion *superR) {
+
+  // At this point we have already checked in either RetrieveElement or
+  // RetrieveField if 'R' has a direct binding.
+
+  RegionBindings B = GetRegionBindings(store);
+
+  while (superR) {
+    if (const Optional<SVal> &D =
+        RetrieveDerivedDefaultValue(B, superR, R, Ty))
+      return *D;
+
+    // If our super region is a field or element itself, walk up the region
+    // hierarchy to see if there is a default value installed in an ancestor.
+    if (const SubRegion *SR = dyn_cast<SubRegion>(superR)) {
+      superR = SR->getSuperRegion();
+      continue;
+    }
+    break;
+  }
+
+  // Lazy binding?
+  Store lazyBindingStore = NULL;
+  const MemRegion *lazyBindingRegion = NULL;
+  llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R);
+
+  if (lazyBindingRegion) {
+    if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
+      return RetrieveElement(lazyBindingStore, ER);
+    return RetrieveField(lazyBindingStore,
+                         cast<FieldRegion>(lazyBindingRegion));
+  }
+
+  if (R->hasStackNonParametersStorage()) {
+    if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+      // Currently we don't reason specially about Clang-style vectors.  Check
+      // if superR is a vector and if so return Unknown.
+      if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) {
+        if (typedSuperR->getValueType()->isVectorType())
+          return UnknownVal();
+      }
+      
+      // FIXME: We also need to take ElementRegions with symbolic indexes into
+      // account.
+      if (!ER->getIndex().isConstant())
+        return UnknownVal();
+    }
+
+    return UndefinedVal();
+  }
+
+  // All other values are symbolic.
+  return svalBuilder.getRegionValueSymbolVal(R);
+}
+
+SVal RegionStoreManager::RetrieveObjCIvar(Store store, const ObjCIvarRegion* R){
+
+    // Check if the region has a binding.
+  RegionBindings B = GetRegionBindings(store);
+
+  if (const Optional<SVal> &V = getDirectBinding(B, R))
+    return *V;
+
+  const MemRegion *superR = R->getSuperRegion();
+
+  // Check if the super region has a default binding.
+  if (const Optional<SVal> &V = getDefaultBinding(B, superR)) {
+    if (SymbolRef parentSym = V->getAsSymbol())
+      return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
+
+    // Other cases: give up.
+    return UnknownVal();
+  }
+
+  return RetrieveLazySymbol(R);
+}
+
+SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
+
+  // Check if the region has a binding.
+  RegionBindings B = GetRegionBindings(store);
+
+  if (const Optional<SVal> &V = getDirectBinding(B, R))
+    return *V;
+
+  // Lazily derive a value for the VarRegion.
+  const VarDecl *VD = R->getDecl();
+  QualType T = VD->getType();
+  const MemSpaceRegion *MS = R->getMemorySpace();
+
+  if (isa<UnknownSpaceRegion>(MS) ||
+      isa<StackArgumentsSpaceRegion>(MS))
+    return svalBuilder.getRegionValueSymbolVal(R);
+
+  if (isa<GlobalsSpaceRegion>(MS)) {
+    if (isa<NonStaticGlobalSpaceRegion>(MS)) {
+      // Is 'VD' declared constant?  If so, retrieve the constant value.
+      QualType CT = Ctx.getCanonicalType(T);
+      if (CT.isConstQualified()) {
+        const Expr *Init = VD->getInit();
+        // Do the null check first, as we want to call 'IgnoreParenCasts'.
+        if (Init)
+          if (const IntegerLiteral *IL =
+              dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
+            const nonloc::ConcreteInt &V = svalBuilder.makeIntVal(IL);
+            return svalBuilder.evalCast(V, Init->getType(), IL->getType());
+          }
+      }
+
+      if (const Optional<SVal> &V = RetrieveDerivedDefaultValue(B, MS, R, CT))
+        return V.getValue();
+
+      return svalBuilder.getRegionValueSymbolVal(R);
+    }
+
+    if (T->isIntegerType())
+      return svalBuilder.makeIntVal(0, T);
+    if (T->isPointerType())
+      return svalBuilder.makeNull();
+
+    return UnknownVal();
+  }
+
+  return UndefinedVal();
+}
+
+SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
+  // All other values are symbolic.
+  return svalBuilder.getRegionValueSymbolVal(R);
+}
+
+SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
+  QualType T = R->getValueType();
+  assert(T->isStructureOrClassType());
+  return svalBuilder.makeLazyCompoundVal(store, R);
+}
+
+SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) {
+  assert(Ctx.getAsConstantArrayType(R->getValueType()));
+  return svalBuilder.makeLazyCompoundVal(store, R);
+}
+
+//===----------------------------------------------------------------------===//
+// Binding values to regions.
+//===----------------------------------------------------------------------===//
+
+Store RegionStoreManager::Remove(Store store, Loc L) {
+  if (isa<loc::MemRegionVal>(L))
+    if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
+      return removeBinding(GetRegionBindings(store), R).getRoot();
+
+  return store;
+}
+
+Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
+  if (isa<loc::ConcreteInt>(L))
+    return store;
+
+  // If we get here, the location should be a region.
+  const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+
+  // Check if the region is a struct region.
+  if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
+    if (TR->getValueType()->isStructureOrClassType())
+      return BindStruct(store, TR, V);
+
+  if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+    if (ER->getIndex().isZeroConstant()) {
+      if (const TypedRegion *superR =
+            dyn_cast<TypedRegion>(ER->getSuperRegion())) {
+        QualType superTy = superR->getValueType();
+        // For now, just invalidate the fields of the struct/union/class.
+        // This is for test rdar_test_7185607 in misc-ps-region-store.m.
+        // FIXME: Precisely handle the fields of the record.
+        if (superTy->isStructureOrClassType())
+          return KillStruct(store, superR, UnknownVal());
+      }
+    }
+  }
+  else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+    // Binding directly to a symbolic region should be treated as binding
+    // to element 0.
+    QualType T = SR->getSymbol()->getType(Ctx);
+
+    // FIXME: Is this the right way to handle symbols that are references?
+    if (const PointerType *PT = T->getAs<PointerType>())
+      T = PT->getPointeeType();
+    else
+      T = T->getAs<ReferenceType>()->getPointeeType();
+
+    R = GetElementZeroRegion(SR, T);
+  }
+
+  // Perform the binding.
+  RegionBindings B = GetRegionBindings(store);
+  return addBinding(B, R, BindingKey::Direct, V).getRoot();
+}
+
+Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
+                                   SVal InitVal) {
+
+  QualType T = VR->getDecl()->getType();
+
+  if (T->isArrayType())
+    return BindArray(store, VR, InitVal);
+  if (T->isStructureOrClassType())
+    return BindStruct(store, VR, InitVal);
+
+  return Bind(store, svalBuilder.makeLoc(VR), InitVal);
+}
+
+// FIXME: this method should be merged into Bind().
+Store RegionStoreManager::BindCompoundLiteral(Store store,
+                                              const CompoundLiteralExpr *CL,
+                                              const LocationContext *LC,
+                                              SVal V) {
+  return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)),
+              V);
+}
+
+
+Store RegionStoreManager::setImplicitDefaultValue(Store store,
+                                                  const MemRegion *R,
+                                                  QualType T) {
+  RegionBindings B = GetRegionBindings(store);
+  SVal V;
+
+  if (Loc::IsLocType(T))
+    V = svalBuilder.makeNull();
+  else if (T->isIntegerType())
+    V = svalBuilder.makeZeroVal(T);
+  else if (T->isStructureOrClassType() || T->isArrayType()) {
+    // Set the default value to a zero constant when it is a structure
+    // or array.  The type doesn't really matter.
+    V = svalBuilder.makeZeroVal(Ctx.IntTy);
+  }
+  else {
+    return store;
+  }
+
+  return addBinding(B, R, BindingKey::Default, V).getRoot();
+}
+
+Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
+                                    SVal Init) {
+
+  const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
+  QualType ElementTy = AT->getElementType();
+  Optional<uint64_t> Size;
+
+  if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
+    Size = CAT->getSize().getZExtValue();
+
+  // Check if the init expr is a string literal.
+  if (loc::MemRegionVal *MRV = dyn_cast<loc::MemRegionVal>(&Init)) {
+    const StringRegion *S = cast<StringRegion>(MRV->getRegion());
+
+    // Treat the string as a lazy compound value.
+    nonloc::LazyCompoundVal LCV =
+      cast<nonloc::LazyCompoundVal>(svalBuilder.makeLazyCompoundVal(store, S));
+    return CopyLazyBindings(LCV, store, R);
+  }
+
+  // Handle lazy compound values.
+  if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&Init))
+    return CopyLazyBindings(*LCV, store, R);
+
+  // Remaining case: explicit compound values.
+
+  if (Init.isUnknown())
+    return setImplicitDefaultValue(store, R, ElementTy);
+
+  nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
+  nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
+  uint64_t i = 0;
+
+  for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) {
+    // The init list might be shorter than the array length.
+    if (VI == VE)
+      break;
+
+    const NonLoc &Idx = svalBuilder.makeArrayIndex(i);
+    const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, Ctx);
+
+    if (ElementTy->isStructureOrClassType())
+      store = BindStruct(store, ER, *VI);
+    else if (ElementTy->isArrayType())
+      store = BindArray(store, ER, *VI);
+    else
+      store = Bind(store, svalBuilder.makeLoc(ER), *VI);
+  }
+
+  // If the init list is shorter than the array length, set the
+  // array default value.
+  if (Size.hasValue() && i < Size.getValue())
+    store = setImplicitDefaultValue(store, R, ElementTy);
+
+  return store;
+}
+
+Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
+                                     SVal V) {
+
+  if (!Features.supportsFields())
+    return store;
+
+  QualType T = R->getValueType();
+  assert(T->isStructureOrClassType());
+
+  const RecordType* RT = T->getAs<RecordType>();
+  RecordDecl* RD = RT->getDecl();
+
+  if (!RD->isDefinition())
+    return store;
+
+  // Handle lazy compound values.
+  if (const nonloc::LazyCompoundVal *LCV=dyn_cast<nonloc::LazyCompoundVal>(&V))
+    return CopyLazyBindings(*LCV, store, R);
+
+  // We may get non-CompoundVal accidentally due to imprecise cast logic or
+  // that we are binding symbolic struct value. Kill the field values, and if
+  // the value is symbolic go and bind it as a "default" binding.
+  if (V.isUnknown() || !isa<nonloc::CompoundVal>(V)) {
+    SVal SV = isa<nonloc::SymbolVal>(V) ? V : UnknownVal();
+    return KillStruct(store, R, SV);
+  }
+
+  nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
+  nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
+
+  RecordDecl::field_iterator FI, FE;
+
+  for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI, ++VI) {
+
+    if (VI == VE)
+      break;
+
+    QualType FTy = (*FI)->getType();
+    const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
+
+    if (FTy->isArrayType())
+      store = BindArray(store, FR, *VI);
+    else if (FTy->isStructureOrClassType())
+      store = BindStruct(store, FR, *VI);
+    else
+      store = Bind(store, svalBuilder.makeLoc(FR), *VI);
+  }
+
+  // There may be fewer values in the initialize list than the fields of struct.
+  if (FI != FE) {
+    RegionBindings B = GetRegionBindings(store);
+    B = addBinding(B, R, BindingKey::Default, svalBuilder.makeIntVal(0, false));
+    store = B.getRoot();
+  }
+
+  return store;
+}
+
+Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R,
+                                     SVal DefaultVal) {
+  RegionBindings B = GetRegionBindings(store);
+  llvm::OwningPtr<RegionStoreSubRegionMap>
+    SubRegions(getRegionStoreSubRegionMap(store));
+  RemoveSubRegionBindings(B, R, *SubRegions);
+
+  // Set the default value of the struct region to "unknown".
+  return addBinding(B, R, BindingKey::Default, DefaultVal).getRoot();
+}
+
+Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
+                                           Store store, const TypedRegion *R) {
+
+  // Nuke the old bindings stemming from R.
+  RegionBindings B = GetRegionBindings(store);
+
+  llvm::OwningPtr<RegionStoreSubRegionMap>
+    SubRegions(getRegionStoreSubRegionMap(store));
+
+  // B and DVM are updated after the call to RemoveSubRegionBindings.
+  RemoveSubRegionBindings(B, R, *SubRegions.get());
+
+  // Now copy the bindings.  This amounts to just binding 'V' to 'R'.  This
+  // results in a zero-copy algorithm.
+  return addBinding(B, R, BindingKey::Direct, V).getRoot();
+}
+
+//===----------------------------------------------------------------------===//
+// "Raw" retrievals and bindings.
+//===----------------------------------------------------------------------===//
+
+
+RegionBindings RegionStoreManager::addBinding(RegionBindings B, BindingKey K,
+                                              SVal V) {
+  if (!K.isValid())
+    return B;
+  return RBFactory.add(B, K, V);
+}
+
+RegionBindings RegionStoreManager::addBinding(RegionBindings B,
+                                              const MemRegion *R,
+                                              BindingKey::Kind k, SVal V) {
+  return addBinding(B, BindingKey::Make(R, k), V);
+}
+
+const SVal *RegionStoreManager::lookup(RegionBindings B, BindingKey K) {
+  if (!K.isValid())
+    return NULL;
+  return B.lookup(K);
+}
+
+const SVal *RegionStoreManager::lookup(RegionBindings B,
+                                       const MemRegion *R,
+                                       BindingKey::Kind k) {
+  return lookup(B, BindingKey::Make(R, k));
+}
+
+RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
+                                                 BindingKey K) {
+  if (!K.isValid())
+    return B;
+  return RBFactory.remove(B, K);
+}
+
+RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
+                                                 const MemRegion *R,
+                                                BindingKey::Kind k){
+  return removeBinding(B, BindingKey::Make(R, k));
+}
+
+//===----------------------------------------------------------------------===//
+// State pruning.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class RemoveDeadBindingsWorker :
+  public ClusterAnalysis<RemoveDeadBindingsWorker> {
+  llvm::SmallVector<const SymbolicRegion*, 12> Postponed;
+  SymbolReaper &SymReaper;
+  const StackFrameContext *CurrentLCtx;
+
+public:
+  RemoveDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr,
+                           RegionBindings b, SymbolReaper &symReaper,
+                           const StackFrameContext *LCtx)
+    : ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b,
+                                                /* includeGlobals = */ false),
+      SymReaper(symReaper), CurrentLCtx(LCtx) {}
+
+  // Called by ClusterAnalysis.
+  void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C);
+  void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
+
+  void VisitBindingKey(BindingKey K);
+  bool UpdatePostponed();
+  void VisitBinding(SVal V);
+};
+}
+
+void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
+                                                   RegionCluster &C) {
+
+  if (const VarRegion *VR = dyn_cast<VarRegion>(baseR)) {
+    if (SymReaper.isLive(VR))
+      AddToWorkList(baseR, C);
+
+    return;
+  }
+
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) {
+    if (SymReaper.isLive(SR->getSymbol()))
+      AddToWorkList(SR, C);
+    else
+      Postponed.push_back(SR);
+
+    return;
+  }
+
+  if (isa<NonStaticGlobalSpaceRegion>(baseR)) {
+    AddToWorkList(baseR, C);
+    return;
+  }
+
+  // CXXThisRegion in the current or parent location context is live.
+  if (const CXXThisRegion *TR = dyn_cast<CXXThisRegion>(baseR)) {
+    const StackArgumentsSpaceRegion *StackReg =
+      cast<StackArgumentsSpaceRegion>(TR->getSuperRegion());
+    const StackFrameContext *RegCtx = StackReg->getStackFrame();
+    if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx))
+      AddToWorkList(TR, C);
+  }
+}
+
+void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
+                                            BindingKey *I, BindingKey *E) {
+  for ( ; I != E; ++I)
+    VisitBindingKey(*I);
+}
+
+void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
+  // Is it a LazyCompoundVal?  All referenced regions are live as well.
+  if (const nonloc::LazyCompoundVal *LCS =
+      dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+    const MemRegion *LazyR = LCS->getRegion();
+    RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+    for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+      const SubRegion *baseR = dyn_cast<SubRegion>(RI.getKey().getRegion());
+      if (baseR && baseR->isSubRegionOf(LazyR))
+        VisitBinding(RI.getData());
+    }
+    return;
+  }
+
+  // If V is a region, then add it to the worklist.
+  if (const MemRegion *R = V.getAsRegion())
+    AddToWorkList(R);
+
+    // Update the set of live symbols.
+  for (SVal::symbol_iterator SI=V.symbol_begin(), SE=V.symbol_end();
+       SI!=SE;++SI)
+    SymReaper.markLive(*SI);
+}
+
+void RemoveDeadBindingsWorker::VisitBindingKey(BindingKey K) {
+  const MemRegion *R = K.getRegion();
+
+  // Mark this region "live" by adding it to the worklist.  This will cause
+  // use to visit all regions in the cluster (if we haven't visited them
+  // already).
+  if (AddToWorkList(R)) {
+    // Mark the symbol for any live SymbolicRegion as "live".  This means we
+    // should continue to track that symbol.
+    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
+      SymReaper.markLive(SymR->getSymbol());
+
+    // For BlockDataRegions, enqueue the VarRegions for variables marked
+    // with __block (passed-by-reference).
+    // via BlockDeclRefExprs.
+    if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
+      for (BlockDataRegion::referenced_vars_iterator
+           RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
+           RI != RE; ++RI) {
+        if ((*RI)->getDecl()->getAttr<BlocksAttr>())
+          AddToWorkList(*RI);
+      }
+
+      // No possible data bindings on a BlockDataRegion.
+      return;
+    }
+  }
+
+  // Visit the data binding for K.
+  if (const SVal *V = RM.lookup(B, K))
+    VisitBinding(*V);
+}
+
+bool RemoveDeadBindingsWorker::UpdatePostponed() {
+  // See if any postponed SymbolicRegions are actually live now, after
+  // having done a scan.
+  bool changed = false;
+
+  for (llvm::SmallVectorImpl<const SymbolicRegion*>::iterator
+        I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) {
+    if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(*I)) {
+      if (SymReaper.isLive(SR->getSymbol())) {
+        changed |= AddToWorkList(SR);
+        *I = NULL;
+      }
+    }
+  }
+
+  return changed;
+}
+
+Store RegionStoreManager::RemoveDeadBindings(Store store,
+                                             const StackFrameContext *LCtx,
+                                             SymbolReaper& SymReaper,
+                           llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+  RegionBindings B = GetRegionBindings(store);
+  RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx);
+  W.GenerateClusters();
+
+  // Enqueue the region roots onto the worklist.
+  for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
+       E=RegionRoots.end(); I!=E; ++I)
+    W.AddToWorkList(*I);
+
+  do W.RunWorkList(); while (W.UpdatePostponed());
+
+  // We have now scanned the store, marking reachable regions and symbols
+  // as live.  We now remove all the regions that are dead from the store
+  // as well as update DSymbols with the set symbols that are now dead.
+  for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+    const BindingKey &K = I.getKey();
+
+    // If the cluster has been visited, we know the region has been marked.
+    if (W.isVisited(K.getRegion()))
+      continue;
+
+    // Remove the dead entry.
+    B = removeBinding(B, K);
+
+    // Mark all non-live symbols that this binding references as dead.
+    if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(K.getRegion()))
+      SymReaper.maybeDead(SymR->getSymbol());
+
+    SVal X = I.getData();
+    SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+    for (; SI != SE; ++SI)
+      SymReaper.maybeDead(*SI);
+  }
+
+  return B.getRoot();
+}
+
+
+Store RegionStoreManager::EnterStackFrame(const GRState *state,
+                                          const StackFrameContext *frame) {
+  FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
+  FunctionDecl::param_const_iterator PI = FD->param_begin();
+  Store store = state->getStore();
+
+  if (CallExpr const *CE = dyn_cast<CallExpr>(frame->getCallSite())) {
+    CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
+
+    // Copy the arg expression value to the arg variables.
+    for (; AI != AE; ++AI, ++PI) {
+      SVal ArgVal = state->getSVal(*AI);
+      store = Bind(store,
+                   svalBuilder.makeLoc(MRMgr.getVarRegion(*PI,frame)), ArgVal);
+    }
+  } else if (const CXXConstructExpr *CE =
+               dyn_cast<CXXConstructExpr>(frame->getCallSite())) {
+    CXXConstructExpr::const_arg_iterator AI = CE->arg_begin(),
+      AE = CE->arg_end();
+
+    // Copy the arg expression value to the arg variables.
+    for (; AI != AE; ++AI, ++PI) {
+      SVal ArgVal = state->getSVal(*AI);
+      store = Bind(store,
+                   svalBuilder.makeLoc(MRMgr.getVarRegion(*PI,frame)), ArgVal);
+    }
+  } else
+    assert(isa<CXXDestructorDecl>(frame->getDecl()));
+
+  return store;
+}
+
+//===----------------------------------------------------------------------===//
+// Utility methods.
+//===----------------------------------------------------------------------===//
+
+void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
+                               const char* nl, const char *sep) {
+  RegionBindings B = GetRegionBindings(store);
+  OS << "Store (direct and default bindings):" << nl;
+
+  for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+    OS << ' ' << I.getKey() << " : " << I.getData() << nl;
+}
diff --git a/lib/StaticAnalyzer/SValBuilder.cpp b/lib/StaticAnalyzer/SValBuilder.cpp
new file mode 100644 (file)
index 0000000..f87fb7e
--- /dev/null
@@ -0,0 +1,310 @@
+// SValBuilder.cpp - Basic class for all SValBuilder implementations -*- 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 SValBuilder, the base class for all (complete) SValBuilder
+//  implementations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/BasicValueFactory.h"
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Basic SVal creation.
+//===----------------------------------------------------------------------===//
+
+DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType T) {
+  if (Loc::IsLocType(T))
+    return makeNull();
+
+  if (T->isIntegerType())
+    return makeIntVal(0, T);
+
+  // FIXME: Handle floats.
+  // FIXME: Handle structs.
+  return UnknownVal();
+}
+
+
+NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+                                const llvm::APSInt& v, QualType T) {
+  // The Environment ensures we always get a persistent APSInt in
+  // BasicValueFactory, so we don't need to get the APSInt from
+  // BasicValueFactory again.
+  assert(!Loc::IsLocType(T));
+  return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, v, T));
+}
+
+NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+                                const SymExpr *rhs, QualType T) {
+  assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
+  assert(!Loc::IsLocType(T));
+  return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, T));
+}
+
+
+SVal SValBuilder::convertToArrayIndex(SVal V) {
+  if (V.isUnknownOrUndef())
+    return V;
+
+  // Common case: we have an appropriately sized integer.
+  if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&V)) {
+    const llvm::APSInt& I = CI->getValue();
+    if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
+      return V;
+  }
+
+  return evalCastNL(cast<NonLoc>(V), ArrayIndexTy);
+}
+
+DefinedOrUnknownSVal 
+SValBuilder::getRegionValueSymbolVal(const TypedRegion* R) {
+  QualType T = R->getValueType();
+
+  if (!SymbolManager::canSymbolicate(T))
+    return UnknownVal();
+
+  SymbolRef sym = SymMgr.getRegionValueSymbol(R);
+
+  if (Loc::IsLocType(T))
+    return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+  return nonloc::SymbolVal(sym);
+}
+
+DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag,
+                                                        const Expr *E,
+                                                        unsigned Count) {
+  QualType T = E->getType();
+
+  if (!SymbolManager::canSymbolicate(T))
+    return UnknownVal();
+
+  SymbolRef sym = SymMgr.getConjuredSymbol(E, Count, SymbolTag);
+
+  if (Loc::IsLocType(T))
+    return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+  return nonloc::SymbolVal(sym);
+}
+
+DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag,
+                                                        const Expr *E,
+                                                        QualType T,
+                                                        unsigned Count) {
+  
+  if (!SymbolManager::canSymbolicate(T))
+    return UnknownVal();
+
+  SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count, SymbolTag);
+
+  if (Loc::IsLocType(T))
+    return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+  return nonloc::SymbolVal(sym);
+}
+
+DefinedSVal SValBuilder::getMetadataSymbolVal(const void *SymbolTag,
+                                               const MemRegion *MR,
+                                               const Expr *E, QualType T,
+                                               unsigned Count) {
+  assert(SymbolManager::canSymbolicate(T) && "Invalid metadata symbol type");
+
+  SymbolRef sym = SymMgr.getMetadataSymbol(MR, E, T, Count, SymbolTag);
+
+  if (Loc::IsLocType(T))
+    return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+  return nonloc::SymbolVal(sym);
+}
+
+DefinedOrUnknownSVal
+SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
+                                             const TypedRegion *R) {
+  QualType T = R->getValueType();
+
+  if (!SymbolManager::canSymbolicate(T))
+    return UnknownVal();
+
+  SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, R);
+
+  if (Loc::IsLocType(T))
+    return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
+
+  return nonloc::SymbolVal(sym);
+}
+
+DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* FD) {
+  return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD));
+}
+
+DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *D,
+                                          CanQualType locTy,
+                                          const LocationContext *LC) {
+  const BlockTextRegion *BC =
+    MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext());
+  const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+  return loc::MemRegionVal(BD);
+}
+
+//===----------------------------------------------------------------------===//
+
+SVal SValBuilder::evalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+                          SVal L, SVal R, QualType T) {
+
+  if (L.isUndef() || R.isUndef())
+    return UndefinedVal();
+
+  if (L.isUnknown() || R.isUnknown())
+    return UnknownVal();
+
+  if (isa<Loc>(L)) {
+    if (isa<Loc>(R))
+      return evalBinOpLL(ST, Op, cast<Loc>(L), cast<Loc>(R), T);
+
+    return evalBinOpLN(ST, Op, cast<Loc>(L), cast<NonLoc>(R), T);
+  }
+
+  if (isa<Loc>(R)) {
+    // Support pointer arithmetic where the addend is on the left
+    // and the pointer on the right.
+    assert(Op == BO_Add);
+
+    // Commute the operands.
+    return evalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T);
+  }
+
+  return evalBinOpNN(ST, Op, cast<NonLoc>(L), cast<NonLoc>(R), T);
+}
+
+DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *ST,
+                                       DefinedOrUnknownSVal L,
+                                       DefinedOrUnknownSVal R) {
+  return cast<DefinedOrUnknownSVal>(evalBinOp(ST, BO_EQ, L, R,
+                                              Context.IntTy));
+}
+
+// FIXME: should rewrite according to the cast kind.
+SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
+  if (val.isUnknownOrUndef() || castTy == originalTy)
+    return val;
+
+  // For const casts, just propagate the value.
+  if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
+    if (Context.hasSameUnqualifiedType(castTy, originalTy))
+      return val;
+
+  // Check for casts to real or complex numbers.  We don't handle these at all
+  // right now.
+  if (castTy->isFloatingType() || castTy->isAnyComplexType())
+    return UnknownVal();
+  
+  // Check for casts from integers to integers.
+  if (castTy->isIntegerType() && originalTy->isIntegerType())
+    return evalCastNL(cast<NonLoc>(val), castTy);
+
+  // Check for casts from pointers to integers.
+  if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
+    return evalCastL(cast<Loc>(val), castTy);
+
+  // Check for casts from integers to pointers.
+  if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) {
+    if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
+      if (const MemRegion *R = LV->getLoc().getAsRegion()) {
+        StoreManager &storeMgr = StateMgr.getStoreManager();
+        R = storeMgr.CastRegion(R, castTy);
+        return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
+      }
+      return LV->getLoc();
+    }
+    goto DispatchCast;
+  }
+
+  // Just pass through function and block pointers.
+  if (originalTy->isBlockPointerType() || originalTy->isFunctionPointerType()) {
+    assert(Loc::IsLocType(castTy));
+    return val;
+  }
+
+  // Check for casts from array type to another type.
+  if (originalTy->isArrayType()) {
+    // We will always decay to a pointer.
+    val = StateMgr.ArrayToPointer(cast<Loc>(val));
+
+    // Are we casting from an array to a pointer?  If so just pass on
+    // the decayed value.
+    if (castTy->isPointerType())
+      return val;
+
+    // Are we casting from an array to an integer?  If so, cast the decayed
+    // pointer value to an integer.
+    assert(castTy->isIntegerType());
+
+    // FIXME: Keep these here for now in case we decide soon that we
+    // need the original decayed type.
+    //    QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
+    //    QualType pointerTy = C.getPointerType(elemTy);
+    return evalCastL(cast<Loc>(val), castTy);
+  }
+
+  // Check for casts from a region to a specific type.
+  if (const MemRegion *R = val.getAsRegion()) {
+    // FIXME: We should handle the case where we strip off view layers to get
+    //  to a desugared type.
+
+    if (!Loc::IsLocType(castTy)) {
+      // FIXME: There can be gross cases where one casts the result of a function
+      // (that returns a pointer) to some other value that happens to fit
+      // within that pointer value.  We currently have no good way to
+      // model such operations.  When this happens, the underlying operation
+      // is that the caller is reasoning about bits.  Conceptually we are
+      // layering a "view" of a location on top of those bits.  Perhaps
+      // we need to be more lazy about mutual possible views, even on an
+      // SVal?  This may be necessary for bit-level reasoning as well.
+      return UnknownVal();
+    }
+
+    // We get a symbolic function pointer for a dereference of a function
+    // pointer, but it is of function type. Example:
+
+    //  struct FPRec {
+    //    void (*my_func)(int * x);
+    //  };
+    //
+    //  int bar(int x);
+    //
+    //  int f1_a(struct FPRec* foo) {
+    //    int x;
+    //    (*foo->my_func)(&x);
+    //    return bar(x)+1; // no-warning
+    //  }
+
+    assert(Loc::IsLocType(originalTy) || originalTy->isFunctionType() ||
+           originalTy->isBlockPointerType());
+
+    StoreManager &storeMgr = StateMgr.getStoreManager();
+
+    // Delegate to store manager to get the result of casting a region to a
+    // different type.  If the MemRegion* returned is NULL, this expression
+    // Evaluates to UnknownVal.
+    R = storeMgr.CastRegion(R, castTy);
+    return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
+  }
+
+DispatchCast:
+  // All other cases.
+  return isa<Loc>(val) ? evalCastL(cast<Loc>(val), castTy)
+                       : evalCastNL(cast<NonLoc>(val), castTy);
+}
diff --git a/lib/StaticAnalyzer/SVals.cpp b/lib/StaticAnalyzer/SVals.cpp
new file mode 100644 (file)
index 0000000..dd8508a
--- /dev/null
@@ -0,0 +1,361 @@
+//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- 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 SVal, Loc, and NonLoc, classes that represent
+//  abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/Basic/IdentifierTable.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::dyn_cast;
+using llvm::cast;
+using llvm::APSInt;
+
+//===----------------------------------------------------------------------===//
+// Symbol iteration within an SVal.
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+// Utility methods.
+//===----------------------------------------------------------------------===//
+
+bool SVal::hasConjuredSymbol() const {
+  if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
+    SymbolRef sym = SV->getSymbol();
+    if (isa<SymbolConjured>(sym))
+      return true;
+  }
+
+  if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
+    const MemRegion *R = RV->getRegion();
+    if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+      SymbolRef sym = SR->getSymbol();
+      if (isa<SymbolConjured>(sym))
+        return true;
+    }
+  }
+
+  return false;
+}
+
+const FunctionDecl *SVal::getAsFunctionDecl() const {
+  if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
+    const MemRegion* R = X->getRegion();
+    if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
+      return CTR->getDecl();
+  }
+
+  return NULL;
+}
+
+/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+///  wraps a symbol, return that SymbolRef.  Otherwise return 0.
+// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
+SymbolRef SVal::getAsLocSymbol() const {
+  if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
+    return X->getLoc().getAsLocSymbol();
+
+  if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
+    const MemRegion *R = X->StripCasts();
+    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
+      return SymR->getSymbol();
+  }
+  return NULL;
+}
+
+/// Get the symbol in the SVal or its base region.
+SymbolRef SVal::getLocSymbolInBase() const {
+  const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);
+
+  if (!X)
+    return 0;
+
+  const MemRegion *R = X->getRegion();
+
+  while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+    if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
+      return SymR->getSymbol();
+    else
+      R = SR->getSuperRegion();
+  }
+
+  return 0;
+}
+
+/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
+///  Otherwise return 0.
+// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
+SymbolRef SVal::getAsSymbol() const {
+  if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+    return X->getSymbol();
+
+  if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
+    if (SymbolRef Y = dyn_cast<SymbolData>(X->getSymbolicExpression()))
+      return Y;
+
+  return getAsLocSymbol();
+}
+
+/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
+///  return that expression.  Otherwise return NULL.
+const SymExpr *SVal::getAsSymbolicExpression() const {
+  if (const nonloc::SymExprVal *X = dyn_cast<nonloc::SymExprVal>(this))
+    return X->getSymbolicExpression();
+
+  return getAsSymbol();
+}
+
+const MemRegion *SVal::getAsRegion() const {
+  if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
+    return X->getRegion();
+
+  if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
+    return X->getLoc().getAsRegion();
+  }
+
+  return 0;
+}
+
+const MemRegion *loc::MemRegionVal::StripCasts() const {
+  const MemRegion *R = getRegion();
+  return R ?  R->StripCasts() : NULL;
+}
+
+bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const {
+  return itr == X.itr;
+}
+
+bool SVal::symbol_iterator::operator!=(const symbol_iterator &X) const {
+  return itr != X.itr;
+}
+
+SVal::symbol_iterator::symbol_iterator(const SymExpr *SE) {
+  itr.push_back(SE);
+  while (!isa<SymbolData>(itr.back())) expand();
+}
+
+SVal::symbol_iterator& SVal::symbol_iterator::operator++() {
+  assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
+  assert(isa<SymbolData>(itr.back()));
+  itr.pop_back();
+  if (!itr.empty())
+    while (!isa<SymbolData>(itr.back())) expand();
+  return *this;
+}
+
+SymbolRef SVal::symbol_iterator::operator*() {
+  assert(!itr.empty() && "attempting to dereference an 'end' iterator");
+  return cast<SymbolData>(itr.back());
+}
+
+void SVal::symbol_iterator::expand() {
+  const SymExpr *SE = itr.back();
+  itr.pop_back();
+
+  if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
+    itr.push_back(SIE->getLHS());
+    return;
+  }
+  else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
+    itr.push_back(SSE->getLHS());
+    itr.push_back(SSE->getRHS());
+    return;
+  }
+
+  assert(false && "unhandled expansion case");
+}
+
+const void *nonloc::LazyCompoundVal::getStore() const {
+  return static_cast<const LazyCompoundValData*>(Data)->getStore();
+}
+
+const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
+  return static_cast<const LazyCompoundValData*>(Data)->getRegion();
+}
+
+//===----------------------------------------------------------------------===//
+// Other Iterators.
+//===----------------------------------------------------------------------===//
+
+nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
+  return getValue()->begin();
+}
+
+nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
+  return getValue()->end();
+}
+
+//===----------------------------------------------------------------------===//
+// Useful predicates.
+//===----------------------------------------------------------------------===//
+
+bool SVal::isConstant() const {
+  return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
+}
+
+bool SVal::isConstant(int I) const {
+  if (isa<loc::ConcreteInt>(*this))
+    return cast<loc::ConcreteInt>(*this).getValue() == I;
+  else if (isa<nonloc::ConcreteInt>(*this))
+    return cast<nonloc::ConcreteInt>(*this).getValue() == I;
+  else
+    return false;
+}
+
+bool SVal::isZeroConstant() const {
+  return isConstant(0);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Transfer function dispatch for Non-Locs.
+//===----------------------------------------------------------------------===//
+
+SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
+                                    BinaryOperator::Opcode Op,
+                                    const nonloc::ConcreteInt& R) const {
+  const llvm::APSInt* X =
+    svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());
+
+  if (X)
+    return nonloc::ConcreteInt(*X);
+  else
+    return UndefinedVal();
+}
+
+nonloc::ConcreteInt
+nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
+  return svalBuilder.makeIntVal(~getValue());
+}
+
+nonloc::ConcreteInt
+nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
+  return svalBuilder.makeIntVal(-getValue());
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function dispatch for Locs.
+//===----------------------------------------------------------------------===//
+
+SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
+                                 BinaryOperator::Opcode Op,
+                                 const loc::ConcreteInt& R) const {
+
+  assert (Op == BO_Add || Op == BO_Sub ||
+          (Op >= BO_LT && Op <= BO_NE));
+
+  const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
+
+  if (X)
+    return loc::ConcreteInt(*X);
+  else
+    return UndefinedVal();
+}
+
+//===----------------------------------------------------------------------===//
+// Pretty-Printing.
+//===----------------------------------------------------------------------===//
+
+void SVal::dump() const { dumpToStream(llvm::errs()); }
+
+void SVal::dumpToStream(llvm::raw_ostream& os) const {
+  switch (getBaseKind()) {
+    case UnknownKind:
+      os << "Unknown";
+      break;
+    case NonLocKind:
+      cast<NonLoc>(this)->dumpToStream(os);
+      break;
+    case LocKind:
+      cast<Loc>(this)->dumpToStream(os);
+      break;
+    case UndefinedKind:
+      os << "Undefined";
+      break;
+    default:
+      assert (false && "Invalid SVal.");
+  }
+}
+
+void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
+  switch (getSubKind()) {
+    case nonloc::ConcreteIntKind: {
+      const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
+      if (C.getValue().isUnsigned())
+        os << C.getValue().getZExtValue();
+      else
+        os << C.getValue().getSExtValue();
+      os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S')
+         << C.getValue().getBitWidth() << 'b';
+      break;
+    }
+    case nonloc::SymbolValKind:
+      os << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
+      break;
+    case nonloc::SymExprValKind: {
+      const nonloc::SymExprVal& C = *cast<nonloc::SymExprVal>(this);
+      const SymExpr *SE = C.getSymbolicExpression();
+      os << SE;
+      break;
+    }
+    case nonloc::LocAsIntegerKind: {
+      const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
+      os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
+      break;
+    }
+    case nonloc::CompoundValKind: {
+      const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
+      os << "compoundVal{";
+      bool first = true;
+      for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
+        if (first) {
+          os << ' '; first = false;
+        }
+        else
+          os << ", ";
+
+        (*I).dumpToStream(os);
+      }
+      os << "}";
+      break;
+    }
+    case nonloc::LazyCompoundValKind: {
+      const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
+      os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
+         << ',' << C.getRegion()
+         << '}';
+      break;
+    }
+    default:
+      assert (false && "Pretty-printed not implemented for this NonLoc.");
+      break;
+  }
+}
+
+void Loc::dumpToStream(llvm::raw_ostream& os) const {
+  switch (getSubKind()) {
+    case loc::ConcreteIntKind:
+      os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
+      break;
+    case loc::GotoLabelKind:
+      os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
+      break;
+    case loc::MemRegionKind:
+      os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
+      break;
+    default:
+      assert(false && "Pretty-printing not implemented for this Loc.");
+      break;
+  }
+}
diff --git a/lib/StaticAnalyzer/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/SimpleConstraintManager.cpp
new file mode 100644 (file)
index 0000000..e54d0ff
--- /dev/null
@@ -0,0 +1,303 @@
+//== SimpleConstraintManager.cpp --------------------------------*- 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 SimpleConstraintManager, a class that holds code shared
+//  between BasicConstraintManager and RangeConstraintManager.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
+
+namespace clang {
+
+namespace ento {
+
+SimpleConstraintManager::~SimpleConstraintManager() {}
+
+bool SimpleConstraintManager::canReasonAbout(SVal X) const {
+  if (nonloc::SymExprVal *SymVal = dyn_cast<nonloc::SymExprVal>(&X)) {
+    const SymExpr *SE = SymVal->getSymbolicExpression();
+
+    if (isa<SymbolData>(SE))
+      return true;
+
+    if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
+      switch (SIE->getOpcode()) {
+          // We don't reason yet about bitwise-constraints on symbolic values.
+        case BO_And:
+        case BO_Or:
+        case BO_Xor:
+          return false;
+        // We don't reason yet about these arithmetic constraints on
+        // symbolic values.
+        case BO_Mul:
+        case BO_Div:
+        case BO_Rem:
+        case BO_Shl:
+        case BO_Shr:
+          return false;
+        // All other cases.
+        default:
+          return true;
+      }
+    }
+
+    return false;
+  }
+
+  return true;
+}
+
+const GRState *SimpleConstraintManager::assume(const GRState *state,
+                                               DefinedSVal Cond,
+                                               bool Assumption) {
+  if (isa<NonLoc>(Cond))
+    return assume(state, cast<NonLoc>(Cond), Assumption);
+  else
+    return assume(state, cast<Loc>(Cond), Assumption);
+}
+
+const GRState *SimpleConstraintManager::assume(const GRState *state, Loc cond,
+                                               bool assumption) {
+  state = assumeAux(state, cond, assumption);
+  return SU.ProcessAssume(state, cond, assumption);
+}
+
+const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
+                                                  Loc Cond, bool Assumption) {
+
+  BasicValueFactory &BasicVals = state->getBasicVals();
+
+  switch (Cond.getSubKind()) {
+  default:
+    assert (false && "'Assume' not implemented for this Loc.");
+    return state;
+
+  case loc::MemRegionKind: {
+    // FIXME: Should this go into the storemanager?
+
+    const MemRegion *R = cast<loc::MemRegionVal>(Cond).getRegion();
+    const SubRegion *SubR = dyn_cast<SubRegion>(R);
+
+    while (SubR) {
+      // FIXME: now we only find the first symbolic region.
+      if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) {
+        const llvm::APSInt &zero = BasicVals.getZeroWithPtrWidth();
+        if (Assumption)
+          return assumeSymNE(state, SymR->getSymbol(), zero, zero);
+        else
+          return assumeSymEQ(state, SymR->getSymbol(), zero, zero);
+      }
+      SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
+    }
+
+    // FALL-THROUGH.
+  }
+
+  case loc::GotoLabelKind:
+    return Assumption ? state : NULL;
+
+  case loc::ConcreteIntKind: {
+    bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
+    bool isFeasible = b ? Assumption : !Assumption;
+    return isFeasible ? state : NULL;
+  }
+  } // end switch
+}
+
+const GRState *SimpleConstraintManager::assume(const GRState *state,
+                                               NonLoc cond,
+                                               bool assumption) {
+  state = assumeAux(state, cond, assumption);
+  return SU.ProcessAssume(state, cond, assumption);
+}
+
+static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
+  // FIXME: This should probably be part of BinaryOperator, since this isn't
+  // the only place it's used. (This code was copied from SimpleSValBuilder.cpp.)
+  switch (op) {
+  default:
+    assert(false && "Invalid opcode.");
+  case BO_LT: return BO_GE;
+  case BO_GT: return BO_LE;
+  case BO_LE: return BO_GT;
+  case BO_GE: return BO_LT;
+  case BO_EQ: return BO_NE;
+  case BO_NE: return BO_EQ;
+  }
+}
+
+const GRState *SimpleConstraintManager::assumeAux(const GRState *state,
+                                                  NonLoc Cond,
+                                                  bool Assumption) {
+
+  // We cannot reason about SymSymExprs,
+  // and can only reason about some SymIntExprs.
+  if (!canReasonAbout(Cond)) {
+    // Just return the current state indicating that the path is feasible.
+    // This may be an over-approximation of what is possible.
+    return state;
+  }
+
+  BasicValueFactory &BasicVals = state->getBasicVals();
+  SymbolManager &SymMgr = state->getSymbolManager();
+
+  switch (Cond.getSubKind()) {
+  default:
+    assert(false && "'Assume' not implemented for this NonLoc");
+
+  case nonloc::SymbolValKind: {
+    nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
+    SymbolRef sym = SV.getSymbol();
+    QualType T =  SymMgr.getType(sym);
+    const llvm::APSInt &zero = BasicVals.getValue(0, T);
+    if (Assumption)
+      return assumeSymNE(state, sym, zero, zero);
+    else
+      return assumeSymEQ(state, sym, zero, zero);
+  }
+
+  case nonloc::SymExprValKind: {
+    nonloc::SymExprVal V = cast<nonloc::SymExprVal>(Cond);
+
+    // For now, we only handle expressions whose RHS is an integer.
+    // All other expressions are assumed to be feasible.
+    const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression());
+    if (!SE)
+      return state;
+
+    BinaryOperator::Opcode op = SE->getOpcode();
+    // Implicitly compare non-comparison expressions to 0.
+    if (!BinaryOperator::isComparisonOp(op)) {
+      QualType T = SymMgr.getType(SE);
+      const llvm::APSInt &zero = BasicVals.getValue(0, T);
+      op = (Assumption ? BO_NE : BO_EQ);
+      return assumeSymRel(state, SE, op, zero);
+    }
+
+    // From here on out, op is the real comparison we'll be testing.
+    if (!Assumption)
+      op = NegateComparison(op);
+  
+    return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
+  }
+
+  case nonloc::ConcreteIntKind: {
+    bool b = cast<nonloc::ConcreteInt>(Cond).getValue() != 0;
+    bool isFeasible = b ? Assumption : !Assumption;
+    return isFeasible ? state : NULL;
+  }
+
+  case nonloc::LocAsIntegerKind:
+    return assumeAux(state, cast<nonloc::LocAsInteger>(Cond).getLoc(),
+                     Assumption);
+  } // end switch
+}
+
+const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state,
+                                                     const SymExpr *LHS,
+                                                     BinaryOperator::Opcode op,
+                                                     const llvm::APSInt& Int) {
+  assert(BinaryOperator::isComparisonOp(op) &&
+         "Non-comparison ops should be rewritten as comparisons to zero.");
+
+   // We only handle simple comparisons of the form "$sym == constant"
+   // or "($sym+constant1) == constant2".
+   // The adjustment is "constant1" in the above expression. It's used to
+   // "slide" the solution range around for modular arithmetic. For example,
+   // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
+   // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
+   // the subclasses of SimpleConstraintManager to handle the adjustment.
+   llvm::APSInt Adjustment;
+
+  // First check if the LHS is a simple symbol reference.
+  SymbolRef Sym = dyn_cast<SymbolData>(LHS);
+  if (Sym) {
+    Adjustment = 0;
+  } else {
+    // Next, see if it's a "($sym+constant1)" expression.
+    const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS);
+
+    // We don't handle "($sym1+$sym2)".
+    // Give up and assume the constraint is feasible.
+    if (!SE)
+      return state;
+
+    // We don't handle "(<expr>+constant1)".
+    // Give up and assume the constraint is feasible.
+    Sym = dyn_cast<SymbolData>(SE->getLHS());
+    if (!Sym)
+      return state;
+
+    // Get the constant out of the expression "($sym+constant1)".
+    switch (SE->getOpcode()) {
+    case BO_Add:
+      Adjustment = SE->getRHS();
+      break;
+    case BO_Sub:
+      Adjustment = -SE->getRHS();
+      break;
+    default:
+      // We don't handle non-additive operators.
+      // Give up and assume the constraint is feasible.
+      return state;
+    }
+  }
+
+  // FIXME: This next section is a hack. It silently converts the integers to
+  // be of the same type as the symbol, which is not always correct. Really the
+  // comparisons should be performed using the Int's type, then mapped back to
+  // the symbol's range of values.
+  GRStateManager &StateMgr = state->getStateManager();
+  ASTContext &Ctx = StateMgr.getContext();
+
+  QualType T = Sym->getType(Ctx);
+  assert(T->isIntegerType() || Loc::IsLocType(T));
+  unsigned bitwidth = Ctx.getTypeSize(T);
+  bool isSymUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+
+  // Convert the adjustment.
+  Adjustment.setIsUnsigned(isSymUnsigned);
+  Adjustment = Adjustment.extOrTrunc(bitwidth);
+
+  // Convert the right-hand side integer.
+  llvm::APSInt ConvertedInt(Int, isSymUnsigned);
+  ConvertedInt = ConvertedInt.extOrTrunc(bitwidth);
+
+  switch (op) {
+  default:
+    // No logic yet for other operators.  assume the constraint is feasible.
+    return state;
+
+  case BO_EQ:
+    return assumeSymEQ(state, Sym, ConvertedInt, Adjustment);
+
+  case BO_NE:
+    return assumeSymNE(state, Sym, ConvertedInt, Adjustment);
+
+  case BO_GT:
+    return assumeSymGT(state, Sym, ConvertedInt, Adjustment);
+
+  case BO_GE:
+    return assumeSymGE(state, Sym, ConvertedInt, Adjustment);
+
+  case BO_LT:
+    return assumeSymLT(state, Sym, ConvertedInt, Adjustment);
+
+  case BO_LE:
+    return assumeSymLE(state, Sym, ConvertedInt, Adjustment);
+  } // end switch
+}
+
+} // end of namespace ento
+
+} // end of namespace clang
diff --git a/lib/StaticAnalyzer/SimpleConstraintManager.h b/lib/StaticAnalyzer/SimpleConstraintManager.h
new file mode 100644 (file)
index 0000000..75f67f7
--- /dev/null
@@ -0,0 +1,93 @@
+//== SimpleConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  Code shared between BasicConstraintManager and RangeConstraintManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
+#define LLVM_CLANG_GR_SIMPLE_CONSTRAINT_MANAGER_H
+
+#include "clang/StaticAnalyzer/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+
+namespace clang {
+
+namespace ento {
+
+class SimpleConstraintManager : public ConstraintManager {
+  SubEngine &SU;
+public:
+  SimpleConstraintManager(SubEngine &subengine) : SU(subengine) {}
+  virtual ~SimpleConstraintManager();
+
+  //===------------------------------------------------------------------===//
+  // Common implementation for the interface provided by ConstraintManager.
+  //===------------------------------------------------------------------===//
+
+  bool canReasonAbout(SVal X) const;
+
+  const GRState *assume(const GRState *state, DefinedSVal Cond,
+                        bool Assumption);
+
+  const GRState *assume(const GRState *state, Loc Cond, bool Assumption);
+
+  const GRState *assume(const GRState *state, NonLoc Cond, bool Assumption);
+
+  const GRState *assumeSymRel(const GRState *state,
+                              const SymExpr *LHS,
+                              BinaryOperator::Opcode op,
+                              const llvm::APSInt& Int);
+
+protected:
+
+  //===------------------------------------------------------------------===//
+  // Interface that subclasses must implement.
+  //===------------------------------------------------------------------===//
+
+  // Each of these is of the form "$sym+Adj <> V", where "<>" is the comparison
+  // operation for the method being invoked.
+  virtual const GRState *assumeSymNE(const GRState *state, SymbolRef sym,
+                                     const llvm::APSInt& V,
+                                     const llvm::APSInt& Adjustment) = 0;
+
+  virtual const GRState *assumeSymEQ(const GRState *state, SymbolRef sym,
+                                     const llvm::APSInt& V,
+                                     const llvm::APSInt& Adjustment) = 0;
+
+  virtual const GRState *assumeSymLT(const GRState *state, SymbolRef sym,
+                                     const llvm::APSInt& V,
+                                     const llvm::APSInt& Adjustment) = 0;
+
+  virtual const GRState *assumeSymGT(const GRState *state, SymbolRef sym,
+                                     const llvm::APSInt& V,
+                                     const llvm::APSInt& Adjustment) = 0;
+
+  virtual const GRState *assumeSymLE(const GRState *state, SymbolRef sym,
+                                     const llvm::APSInt& V,
+                                     const llvm::APSInt& Adjustment) = 0;
+
+  virtual const GRState *assumeSymGE(const GRState *state, SymbolRef sym,
+                                     const llvm::APSInt& V,
+                                     const llvm::APSInt& Adjustment) = 0;
+
+  //===------------------------------------------------------------------===//
+  // Internal implementation.
+  //===------------------------------------------------------------------===//
+
+  const GRState *assumeAux(const GRState *state, Loc Cond,bool Assumption);
+
+  const GRState *assumeAux(const GRState *state, NonLoc Cond, bool Assumption);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/lib/StaticAnalyzer/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/SimpleSValBuilder.cpp
new file mode 100644 (file)
index 0000000..f1a9074
--- /dev/null
@@ -0,0 +1,884 @@
+// SimpleSValBuilder.cpp - A basic SValBuilder -----------------------*- 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 SimpleSValBuilder, a basic implementation of SValBuilder.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class SimpleSValBuilder : public SValBuilder {
+protected:
+  virtual SVal evalCastNL(NonLoc val, QualType castTy);
+  virtual SVal evalCastL(Loc val, QualType castTy);
+
+public:
+  SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+                    GRStateManager &stateMgr)
+                    : SValBuilder(alloc, context, stateMgr) {}
+  virtual ~SimpleSValBuilder() {}
+
+  virtual SVal evalMinus(NonLoc val);
+  virtual SVal evalComplement(NonLoc val);
+  virtual SVal evalBinOpNN(const GRState *state, BinaryOperator::Opcode op,
+                           NonLoc lhs, NonLoc rhs, QualType resultTy);
+  virtual SVal evalBinOpLL(const GRState *state, BinaryOperator::Opcode op,
+                           Loc lhs, Loc rhs, QualType resultTy);
+  virtual SVal evalBinOpLN(const GRState *state, BinaryOperator::Opcode op,
+                           Loc lhs, NonLoc rhs, QualType resultTy);
+
+  /// getKnownValue - evaluates a given SVal. If the SVal has only one possible
+  ///  (integer) value, that value is returned. Otherwise, returns NULL.
+  virtual const llvm::APSInt *getKnownValue(const GRState *state, SVal V);
+  
+  SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
+                     const llvm::APSInt &RHS, QualType resultTy);
+};
+} // end anonymous namespace
+
+SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
+                                           ASTContext &context,
+                                           GRStateManager &stateMgr) {
+  return new SimpleSValBuilder(alloc, context, stateMgr);
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for Casts.
+//===----------------------------------------------------------------------===//
+
+SVal SimpleSValBuilder::evalCastNL(NonLoc val, QualType castTy) {
+
+  bool isLocType = Loc::IsLocType(castTy);
+
+  if (nonloc::LocAsInteger *LI = dyn_cast<nonloc::LocAsInteger>(&val)) {
+    if (isLocType)
+      return LI->getLoc();
+
+    // FIXME: Correctly support promotions/truncations.
+    unsigned castSize = Context.getTypeSize(castTy);
+    if (castSize == LI->getNumBits())
+      return val;
+    return makeLocAsInteger(LI->getLoc(), castSize);
+  }
+
+  if (const SymExpr *se = val.getAsSymbolicExpression()) {
+    QualType T = Context.getCanonicalType(se->getType(Context));
+    if (T == Context.getCanonicalType(castTy))
+      return val;
+    
+    // FIXME: Remove this hack when we support symbolic truncation/extension.
+    // HACK: If both castTy and T are integers, ignore the cast.  This is
+    // not a permanent solution.  Eventually we want to precisely handle
+    // extension/truncation of symbolic integers.  This prevents us from losing
+    // precision when we assign 'x = y' and 'y' is symbolic and x and y are
+    // different integer types.
+    if (T->isIntegerType() && castTy->isIntegerType())
+      return val;
+
+    return UnknownVal();
+  }
+
+  if (!isa<nonloc::ConcreteInt>(val))
+    return UnknownVal();
+
+  // Only handle casts from integers to integers.
+  if (!isLocType && !castTy->isIntegerType())
+    return UnknownVal();
+
+  llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
+  i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+  i = i.extOrTrunc(Context.getTypeSize(castTy));
+
+  if (isLocType)
+    return makeIntLocVal(i);
+  else
+    return makeIntVal(i);
+}
+
+SVal SimpleSValBuilder::evalCastL(Loc val, QualType castTy) {
+
+  // Casts from pointers -> pointers, just return the lval.
+  //
+  // Casts from pointers -> references, just return the lval.  These
+  //   can be introduced by the frontend for corner cases, e.g
+  //   casting from va_list* to __builtin_va_list&.
+  //
+  if (Loc::IsLocType(castTy) || castTy->isReferenceType())
+    return val;
+
+  // FIXME: Handle transparent unions where a value can be "transparently"
+  //  lifted into a union type.
+  if (castTy->isUnionType())
+    return UnknownVal();
+
+  if (castTy->isIntegerType()) {
+    unsigned BitWidth = Context.getTypeSize(castTy);
+
+    if (!isa<loc::ConcreteInt>(val))
+      return makeLocAsInteger(val, BitWidth);
+
+    llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+    i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+    i = i.extOrTrunc(BitWidth);
+    return makeIntVal(i);
+  }
+
+  // All other cases: return 'UnknownVal'.  This includes casting pointers
+  // to floats, which is probably badness it itself, but this is a good
+  // intermediate solution until we do something better.
+  return UnknownVal();
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for unary operators.
+//===----------------------------------------------------------------------===//
+
+SVal SimpleSValBuilder::evalMinus(NonLoc val) {
+  switch (val.getSubKind()) {
+  case nonloc::ConcreteIntKind:
+    return cast<nonloc::ConcreteInt>(val).evalMinus(*this);
+  default:
+    return UnknownVal();
+  }
+}
+
+SVal SimpleSValBuilder::evalComplement(NonLoc X) {
+  switch (X.getSubKind()) {
+  case nonloc::ConcreteIntKind:
+    return cast<nonloc::ConcreteInt>(X).evalComplement(*this);
+  default:
+    return UnknownVal();
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// Transfer function for binary operators.
+//===----------------------------------------------------------------------===//
+
+static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
+  switch (op) {
+  default:
+    assert(false && "Invalid opcode.");
+  case BO_LT: return BO_GE;
+  case BO_GT: return BO_LE;
+  case BO_LE: return BO_GT;
+  case BO_GE: return BO_LT;
+  case BO_EQ: return BO_NE;
+  case BO_NE: return BO_EQ;
+  }
+}
+
+static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) {
+  switch (op) {
+  default:
+    assert(false && "Invalid opcode.");
+  case BO_LT: return BO_GT;
+  case BO_GT: return BO_LT;
+  case BO_LE: return BO_GE;
+  case BO_GE: return BO_LE;
+  case BO_EQ:
+  case BO_NE:
+    return op;
+  }
+}
+
+SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
+                                    BinaryOperator::Opcode op,
+                                    const llvm::APSInt &RHS,
+                                    QualType resultTy) {
+  bool isIdempotent = false;
+
+  // Check for a few special cases with known reductions first.
+  switch (op) {
+  default:
+    // We can't reduce this case; just treat it normally.
+    break;
+  case BO_Mul:
+    // a*0 and a*1
+    if (RHS == 0)
+      return makeIntVal(0, resultTy);
+    else if (RHS == 1)
+      isIdempotent = true;
+    break;
+  case BO_Div:
+    // a/0 and a/1
+    if (RHS == 0)
+      // This is also handled elsewhere.
+      return UndefinedVal();
+    else if (RHS == 1)
+      isIdempotent = true;
+    break;
+  case BO_Rem:
+    // a%0 and a%1
+    if (RHS == 0)
+      // This is also handled elsewhere.
+      return UndefinedVal();
+    else if (RHS == 1)
+      return makeIntVal(0, resultTy);
+    break;
+  case BO_Add:
+  case BO_Sub:
+  case BO_Shl:
+  case BO_Shr:
+  case BO_Xor:
+    // a+0, a-0, a<<0, a>>0, a^0
+    if (RHS == 0)
+      isIdempotent = true;
+    break;
+  case BO_And:
+    // a&0 and a&(~0)
+    if (RHS == 0)
+      return makeIntVal(0, resultTy);
+    else if (RHS.isAllOnesValue())
+      isIdempotent = true;
+    break;
+  case BO_Or:
+    // a|0 and a|(~0)
+    if (RHS == 0)
+      isIdempotent = true;
+    else if (RHS.isAllOnesValue()) {
+      const llvm::APSInt &Result = BasicVals.Convert(resultTy, RHS);
+      return nonloc::ConcreteInt(Result);
+    }
+    break;
+  }
+
+  // Idempotent ops (like a*1) can still change the type of an expression.
+  // Wrap the LHS up in a NonLoc again and let evalCastNL do the dirty work.
+  if (isIdempotent) {
+    if (SymbolRef LHSSym = dyn_cast<SymbolData>(LHS))
+      return evalCastNL(nonloc::SymbolVal(LHSSym), resultTy);
+    return evalCastNL(nonloc::SymExprVal(LHS), resultTy);
+  }
+
+  // If we reach this point, the expression cannot be simplified.
+  // Make a SymExprVal for the entire thing.
+  return makeNonLoc(LHS, op, RHS, resultTy);
+}
+
+SVal SimpleSValBuilder::evalBinOpNN(const GRState *state,
+                                  BinaryOperator::Opcode op,
+                                  NonLoc lhs, NonLoc rhs,
+                                  QualType resultTy)  {
+  // Handle trivial case where left-side and right-side are the same.
+  if (lhs == rhs)
+    switch (op) {
+      default:
+        break;
+      case BO_EQ:
+      case BO_LE:
+      case BO_GE:
+        return makeTruthVal(true, resultTy);
+      case BO_LT:
+      case BO_GT:
+      case BO_NE:
+        return makeTruthVal(false, resultTy);
+      case BO_Xor:
+      case BO_Sub:
+        return makeIntVal(0, resultTy);
+      case BO_Or:
+      case BO_And:
+        return evalCastNL(lhs, resultTy);
+    }
+
+  while (1) {
+    switch (lhs.getSubKind()) {
+    default:
+      return UnknownVal();
+    case nonloc::LocAsIntegerKind: {
+      Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
+      switch (rhs.getSubKind()) {
+        case nonloc::LocAsIntegerKind:
+          return evalBinOpLL(state, op, lhsL,
+                             cast<nonloc::LocAsInteger>(rhs).getLoc(),
+                             resultTy);
+        case nonloc::ConcreteIntKind: {
+          // Transform the integer into a location and compare.
+          llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
+          i.setIsUnsigned(true);
+          i = i.extOrTrunc(Context.getTypeSize(Context.VoidPtrTy));
+          return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
+        }
+        default:
+          switch (op) {
+            case BO_EQ:
+              return makeTruthVal(false, resultTy);
+            case BO_NE:
+              return makeTruthVal(true, resultTy);
+            default:
+              // This case also handles pointer arithmetic.
+              return UnknownVal();
+          }
+      }
+    }
+    case nonloc::SymExprValKind: {
+      nonloc::SymExprVal *selhs = cast<nonloc::SymExprVal>(&lhs);
+
+      // Only handle LHS of the form "$sym op constant", at least for now.
+      const SymIntExpr *symIntExpr =
+        dyn_cast<SymIntExpr>(selhs->getSymbolicExpression());
+
+      if (!symIntExpr)
+        return UnknownVal();
+
+      // Is this a logical not? (!x is represented as x == 0.)
+      if (op == BO_EQ && rhs.isZeroConstant()) {
+        // We know how to negate certain expressions. Simplify them here.
+
+        BinaryOperator::Opcode opc = symIntExpr->getOpcode();
+        switch (opc) {
+        default:
+          // We don't know how to negate this operation.
+          // Just handle it as if it were a normal comparison to 0.
+          break;
+        case BO_LAnd:
+        case BO_LOr:
+          assert(false && "Logical operators handled by branching logic.");
+          return UnknownVal();
+        case BO_Assign:
+        case BO_MulAssign:
+        case BO_DivAssign:
+        case BO_RemAssign:
+        case BO_AddAssign:
+        case BO_SubAssign:
+        case BO_ShlAssign:
+        case BO_ShrAssign:
+        case BO_AndAssign:
+        case BO_XorAssign:
+        case BO_OrAssign:
+        case BO_Comma:
+          assert(false && "'=' and ',' operators handled by ExprEngine.");
+          return UnknownVal();
+        case BO_PtrMemD:
+        case BO_PtrMemI:
+          assert(false && "Pointer arithmetic not handled here.");
+          return UnknownVal();
+        case BO_LT:
+        case BO_GT:
+        case BO_LE:
+        case BO_GE:
+        case BO_EQ:
+        case BO_NE:
+          // Negate the comparison and make a value.
+          opc = NegateComparison(opc);
+          assert(symIntExpr->getType(Context) == resultTy);
+          return makeNonLoc(symIntExpr->getLHS(), opc,
+                                   symIntExpr->getRHS(), resultTy);
+        }
+      }
+
+      // For now, only handle expressions whose RHS is a constant.
+      const nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs);
+      if (!rhsInt)
+        return UnknownVal();
+
+      // If both the LHS and the current expression are additive,
+      // fold their constants.
+      if (BinaryOperator::isAdditiveOp(op)) {
+        BinaryOperator::Opcode lop = symIntExpr->getOpcode();
+        if (BinaryOperator::isAdditiveOp(lop)) {
+          // resultTy may not be the best type to convert to, but it's
+          // probably the best choice in expressions with mixed type
+          // (such as x+1U+2LL). The rules for implicit conversions should
+          // choose a reasonable type to preserve the expression, and will
+          // at least match how the value is going to be used.
+          const llvm::APSInt &first =
+            BasicVals.Convert(resultTy, symIntExpr->getRHS());
+          const llvm::APSInt &second =
+            BasicVals.Convert(resultTy, rhsInt->getValue());
+          const llvm::APSInt *newRHS;
+          if (lop == op)
+            newRHS = BasicVals.evalAPSInt(BO_Add, first, second);
+          else
+            newRHS = BasicVals.evalAPSInt(BO_Sub, first, second);
+          return MakeSymIntVal(symIntExpr->getLHS(), lop, *newRHS, resultTy);
+        }
+      }
+
+      // Otherwise, make a SymExprVal out of the expression.
+      return MakeSymIntVal(symIntExpr, op, rhsInt->getValue(), resultTy);
+    }
+    case nonloc::ConcreteIntKind: {
+      const nonloc::ConcreteInt& lhsInt = cast<nonloc::ConcreteInt>(lhs);
+
+      if (isa<nonloc::ConcreteInt>(rhs)) {
+        return lhsInt.evalBinOp(*this, op, cast<nonloc::ConcreteInt>(rhs));
+      } else {
+        const llvm::APSInt& lhsValue = lhsInt.getValue();
+        
+        // Swap the left and right sides and flip the operator if doing so
+        // allows us to better reason about the expression (this is a form
+        // of expression canonicalization).
+        // While we're at it, catch some special cases for non-commutative ops.
+        NonLoc tmp = rhs;
+        rhs = lhs;
+        lhs = tmp;
+
+        switch (op) {
+          case BO_LT:
+          case BO_GT:
+          case BO_LE:
+          case BO_GE:
+            op = ReverseComparison(op);
+            continue;
+          case BO_EQ:
+          case BO_NE:
+          case BO_Add:
+          case BO_Mul:
+          case BO_And:
+          case BO_Xor:
+          case BO_Or:
+            continue;
+          case BO_Shr:
+            if (lhsValue.isAllOnesValue() && lhsValue.isSigned())
+              // At this point lhs and rhs have been swapped.
+              return rhs;
+            // FALL-THROUGH
+          case BO_Shl:
+            if (lhsValue == 0)
+              // At this point lhs and rhs have been swapped.
+              return rhs;
+            return UnknownVal();
+          default:
+            return UnknownVal();
+        }
+      }
+    }
+    case nonloc::SymbolValKind: {
+      nonloc::SymbolVal *slhs = cast<nonloc::SymbolVal>(&lhs);
+      SymbolRef Sym = slhs->getSymbol();
+      // Does the symbol simplify to a constant?  If so, "fold" the constant
+      // by setting 'lhs' to a ConcreteInt and try again.
+      if (Sym->getType(Context)->isIntegerType())
+        if (const llvm::APSInt *Constant = state->getSymVal(Sym)) {
+          // The symbol evaluates to a constant. If necessary, promote the
+          // folded constant (LHS) to the result type.
+          const llvm::APSInt &lhs_I = BasicVals.Convert(resultTy, *Constant);
+          lhs = nonloc::ConcreteInt(lhs_I);
+          
+          // Also promote the RHS (if necessary).
+
+          // For shifts, it is not necessary to promote the RHS.
+          if (BinaryOperator::isShiftOp(op))
+            continue;
+          
+          // Other operators: do an implicit conversion.  This shouldn't be
+          // necessary once we support truncation/extension of symbolic values.
+          if (nonloc::ConcreteInt *rhs_I = dyn_cast<nonloc::ConcreteInt>(&rhs)){
+            rhs = nonloc::ConcreteInt(BasicVals.Convert(resultTy,
+                                                        rhs_I->getValue()));
+          }
+          
+          continue;
+        }
+
+      // Is the RHS a symbol we can simplify?
+      if (const nonloc::SymbolVal *srhs = dyn_cast<nonloc::SymbolVal>(&rhs)) {
+        SymbolRef RSym = srhs->getSymbol();
+        if (RSym->getType(Context)->isIntegerType()) {
+          if (const llvm::APSInt *Constant = state->getSymVal(RSym)) {
+            // The symbol evaluates to a constant.
+            const llvm::APSInt &rhs_I = BasicVals.Convert(resultTy, *Constant);
+            rhs = nonloc::ConcreteInt(rhs_I);
+          }
+        }
+      }
+
+      if (isa<nonloc::ConcreteInt>(rhs)) {
+        return MakeSymIntVal(slhs->getSymbol(), op,
+                             cast<nonloc::ConcreteInt>(rhs).getValue(),
+                             resultTy);
+      }
+
+      return UnknownVal();
+    }
+    }
+  }
+}
+
+// FIXME: all this logic will change if/when we have MemRegion::getLocation().
+SVal SimpleSValBuilder::evalBinOpLL(const GRState *state,
+                                  BinaryOperator::Opcode op,
+                                  Loc lhs, Loc rhs,
+                                  QualType resultTy) {
+  // Only comparisons and subtractions are valid operations on two pointers.
+  // See [C99 6.5.5 through 6.5.14] or [C++0x 5.6 through 5.15].
+  // However, if a pointer is casted to an integer, evalBinOpNN may end up
+  // calling this function with another operation (PR7527). We don't attempt to
+  // model this for now, but it could be useful, particularly when the
+  // "location" is actually an integer value that's been passed through a void*.
+  if (!(BinaryOperator::isComparisonOp(op) || op == BO_Sub))
+    return UnknownVal();
+
+  // Special cases for when both sides are identical.
+  if (lhs == rhs) {
+    switch (op) {
+    default:
+      assert(false && "Unimplemented operation for two identical values");
+      return UnknownVal();
+    case BO_Sub:
+      return makeZeroVal(resultTy);
+    case BO_EQ:
+    case BO_LE:
+    case BO_GE:
+      return makeTruthVal(true, resultTy);
+    case BO_NE:
+    case BO_LT:
+    case BO_GT:
+      return makeTruthVal(false, resultTy);
+    }
+  }
+
+  switch (lhs.getSubKind()) {
+  default:
+    assert(false && "Ordering not implemented for this Loc.");
+    return UnknownVal();
+
+  case loc::GotoLabelKind:
+    // The only thing we know about labels is that they're non-null.
+    if (rhs.isZeroConstant()) {
+      switch (op) {
+      default:
+        break;
+      case BO_Sub:
+        return evalCastL(lhs, resultTy);
+      case BO_EQ:
+      case BO_LE:
+      case BO_LT:
+        return makeTruthVal(false, resultTy);
+      case BO_NE:
+      case BO_GT:
+      case BO_GE:
+        return makeTruthVal(true, resultTy);
+      }
+    }
+    // There may be two labels for the same location, and a function region may
+    // have the same address as a label at the start of the function (depending
+    // on the ABI).
+    // FIXME: we can probably do a comparison against other MemRegions, though.
+    // FIXME: is there a way to tell if two labels refer to the same location?
+    return UnknownVal(); 
+
+  case loc::ConcreteIntKind: {
+    // If one of the operands is a symbol and the other is a constant,
+    // build an expression for use by the constraint manager.
+    if (SymbolRef rSym = rhs.getAsLocSymbol()) {
+      // We can only build expressions with symbols on the left,
+      // so we need a reversible operator.
+      if (!BinaryOperator::isComparisonOp(op))
+        return UnknownVal();
+
+      const llvm::APSInt &lVal = cast<loc::ConcreteInt>(lhs).getValue();
+      return makeNonLoc(rSym, ReverseComparison(op), lVal, resultTy);
+    }
+
+    // If both operands are constants, just perform the operation.
+    if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
+      SVal ResultVal = cast<loc::ConcreteInt>(lhs).evalBinOp(BasicVals, op,
+                                                             *rInt);
+      if (Loc *Result = dyn_cast<Loc>(&ResultVal))
+        return evalCastL(*Result, resultTy);
+      else
+        return UnknownVal();
+    }
+
+    // Special case comparisons against NULL.
+    // This must come after the test if the RHS is a symbol, which is used to
+    // build constraints. The address of any non-symbolic region is guaranteed
+    // to be non-NULL, as is any label.
+    assert(isa<loc::MemRegionVal>(rhs) || isa<loc::GotoLabel>(rhs));
+    if (lhs.isZeroConstant()) {
+      switch (op) {
+      default:
+        break;
+      case BO_EQ:
+      case BO_GT:
+      case BO_GE:
+        return makeTruthVal(false, resultTy);
+      case BO_NE:
+      case BO_LT:
+      case BO_LE:
+        return makeTruthVal(true, resultTy);
+      }
+    }
+
+    // Comparing an arbitrary integer to a region or label address is
+    // completely unknowable.
+    return UnknownVal();
+  }
+  case loc::MemRegionKind: {
+    if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
+      // If one of the operands is a symbol and the other is a constant,
+      // build an expression for use by the constraint manager.
+      if (SymbolRef lSym = lhs.getAsLocSymbol())
+        return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy);
+
+      // Special case comparisons to NULL.
+      // This must come after the test if the LHS is a symbol, which is used to
+      // build constraints. The address of any non-symbolic region is guaranteed
+      // to be non-NULL.
+      if (rInt->isZeroConstant()) {
+        switch (op) {
+        default:
+          break;
+        case BO_Sub:
+          return evalCastL(lhs, resultTy);
+        case BO_EQ:
+        case BO_LT:
+        case BO_LE:
+          return makeTruthVal(false, resultTy);
+        case BO_NE:
+        case BO_GT:
+        case BO_GE:
+          return makeTruthVal(true, resultTy);
+        }
+      }
+
+      // Comparing a region to an arbitrary integer is completely unknowable.
+      return UnknownVal();
+    }
+
+    // Get both values as regions, if possible.
+    const MemRegion *LeftMR = lhs.getAsRegion();
+    assert(LeftMR && "MemRegionKind SVal doesn't have a region!");
+
+    const MemRegion *RightMR = rhs.getAsRegion();
+    if (!RightMR)
+      // The RHS is probably a label, which in theory could address a region.
+      // FIXME: we can probably make a more useful statement about non-code
+      // regions, though.
+      return UnknownVal();
+
+    // If both values wrap regions, see if they're from different base regions.
+    const MemRegion *LeftBase = LeftMR->getBaseRegion();
+    const MemRegion *RightBase = RightMR->getBaseRegion();
+    if (LeftBase != RightBase &&
+        !isa<SymbolicRegion>(LeftBase) && !isa<SymbolicRegion>(RightBase)) {
+      switch (op) {
+      default:
+        return UnknownVal();
+      case BO_EQ:
+        return makeTruthVal(false, resultTy);
+      case BO_NE:
+        return makeTruthVal(true, resultTy);
+      }
+    }
+
+    // The two regions are from the same base region. See if they're both a
+    // type of region we know how to compare.
+
+    // FIXME: If/when there is a getAsRawOffset() for FieldRegions, this
+    // ElementRegion path and the FieldRegion path below should be unified.
+    if (const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR)) {
+      // First see if the right region is also an ElementRegion.
+      const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
+      if (!RightER)
+        return UnknownVal();
+
+      // Next, see if the two ERs have the same super-region and matching types.
+      // FIXME: This should do something useful even if the types don't match,
+      // though if both indexes are constant the RegionRawOffset path will
+      // give the correct answer.
+      if (LeftER->getSuperRegion() == RightER->getSuperRegion() &&
+          LeftER->getElementType() == RightER->getElementType()) {
+        // Get the left index and cast it to the correct type.
+        // If the index is unknown or undefined, bail out here.
+        SVal LeftIndexVal = LeftER->getIndex();
+        NonLoc *LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
+        if (!LeftIndex)
+          return UnknownVal();
+        LeftIndexVal = evalCastNL(*LeftIndex, resultTy);
+        LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
+        if (!LeftIndex)
+          return UnknownVal();
+
+        // Do the same for the right index.
+        SVal RightIndexVal = RightER->getIndex();
+        NonLoc *RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
+        if (!RightIndex)
+          return UnknownVal();
+        RightIndexVal = evalCastNL(*RightIndex, resultTy);
+        RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
+        if (!RightIndex)
+          return UnknownVal();
+
+        // Actually perform the operation.
+        // evalBinOpNN expects the two indexes to already be the right type.
+        return evalBinOpNN(state, op, *LeftIndex, *RightIndex, resultTy);
+      }
+
+      // If the element indexes aren't comparable, see if the raw offsets are.
+      RegionRawOffset LeftOffset = LeftER->getAsArrayOffset();
+      RegionRawOffset RightOffset = RightER->getAsArrayOffset();
+
+      if (LeftOffset.getRegion() != NULL &&
+          LeftOffset.getRegion() == RightOffset.getRegion()) {
+        int64_t left = LeftOffset.getByteOffset();
+        int64_t right = RightOffset.getByteOffset();
+
+        switch (op) {
+        default:
+          return UnknownVal();
+        case BO_LT:
+          return makeTruthVal(left < right, resultTy);
+        case BO_GT:
+          return makeTruthVal(left > right, resultTy);
+        case BO_LE:
+          return makeTruthVal(left <= right, resultTy);
+        case BO_GE:
+          return makeTruthVal(left >= right, resultTy);
+        case BO_EQ:
+          return makeTruthVal(left == right, resultTy);
+        case BO_NE:
+          return makeTruthVal(left != right, resultTy);
+        }
+      }
+
+      // If we get here, we have no way of comparing the ElementRegions.
+      return UnknownVal();
+    }
+
+    // See if both regions are fields of the same structure.
+    // FIXME: This doesn't handle nesting, inheritance, or Objective-C ivars.
+    if (const FieldRegion *LeftFR = dyn_cast<FieldRegion>(LeftMR)) {
+      // Only comparisons are meaningful here!
+      if (!BinaryOperator::isComparisonOp(op))
+        return UnknownVal();
+
+      // First see if the right region is also a FieldRegion.
+      const FieldRegion *RightFR = dyn_cast<FieldRegion>(RightMR);
+      if (!RightFR)
+        return UnknownVal();
+
+      // Next, see if the two FRs have the same super-region.
+      // FIXME: This doesn't handle casts yet, and simply stripping the casts
+      // doesn't help.
+      if (LeftFR->getSuperRegion() != RightFR->getSuperRegion())
+        return UnknownVal();
+
+      const FieldDecl *LeftFD = LeftFR->getDecl();
+      const FieldDecl *RightFD = RightFR->getDecl();
+      const RecordDecl *RD = LeftFD->getParent();
+
+      // Make sure the two FRs are from the same kind of record. Just in case!
+      // FIXME: This is probably where inheritance would be a problem.
+      if (RD != RightFD->getParent())
+        return UnknownVal();
+
+      // We know for sure that the two fields are not the same, since that
+      // would have given us the same SVal.
+      if (op == BO_EQ)
+        return makeTruthVal(false, resultTy);
+      if (op == BO_NE)
+        return makeTruthVal(true, resultTy);
+
+      // Iterate through the fields and see which one comes first.
+      // [C99 6.7.2.1.13] "Within a structure object, the non-bit-field
+      // members and the units in which bit-fields reside have addresses that
+      // increase in the order in which they are declared."
+      bool leftFirst = (op == BO_LT || op == BO_LE);
+      for (RecordDecl::field_iterator I = RD->field_begin(),
+           E = RD->field_end(); I!=E; ++I) {
+        if (*I == LeftFD)
+          return makeTruthVal(leftFirst, resultTy);
+        if (*I == RightFD)
+          return makeTruthVal(!leftFirst, resultTy);
+      }
+
+      assert(false && "Fields not found in parent record's definition");
+    }
+
+    // If we get here, we have no way of comparing the regions.
+    return UnknownVal();
+  }
+  }
+}
+
+SVal SimpleSValBuilder::evalBinOpLN(const GRState *state,
+                                  BinaryOperator::Opcode op,
+                                  Loc lhs, NonLoc rhs, QualType resultTy) {
+  // Special case: 'rhs' is an integer that has the same width as a pointer and
+  // we are using the integer location in a comparison.  Normally this cannot be
+  // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+  // can generate comparisons that trigger this code.
+  // FIXME: Are all locations guaranteed to have pointer width?
+  if (BinaryOperator::isComparisonOp(op)) {
+    if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
+      const llvm::APSInt *x = &rhsInt->getValue();
+      ASTContext &ctx = Context;
+      if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
+        // Convert the signedness of the integer (if necessary).
+        if (x->isSigned())
+          x = &getBasicValueFactory().getValue(*x, true);
+
+        return evalBinOpLL(state, op, lhs, loc::ConcreteInt(*x), resultTy);
+      }
+    }
+  }
+  
+  // We are dealing with pointer arithmetic.
+
+  // Handle pointer arithmetic on constant values.
+  if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
+    if (loc::ConcreteInt *lhsInt = dyn_cast<loc::ConcreteInt>(&lhs)) {
+      const llvm::APSInt &leftI = lhsInt->getValue();
+      assert(leftI.isUnsigned());
+      llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);
+
+      // Convert the bitwidth of rightI.  This should deal with overflow
+      // since we are dealing with concrete values.
+      rightI = rightI.extOrTrunc(leftI.getBitWidth());
+
+      // Offset the increment by the pointer size.
+      llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
+      rightI *= Multiplicand;
+      
+      // Compute the adjusted pointer.
+      switch (op) {
+        case BO_Add:
+          rightI = leftI + rightI;
+          break;
+        case BO_Sub:
+          rightI = leftI - rightI;
+          break;
+        default:
+          llvm_unreachable("Invalid pointer arithmetic operation");
+      }
+      return loc::ConcreteInt(getBasicValueFactory().getValue(rightI));
+    }
+  }
+  
+
+  // Delegate remaining pointer arithmetic to the StoreManager.
+  return state->getStateManager().getStoreManager().evalBinOp(op, lhs,
+                                                              rhs, resultTy);
+}
+
+const llvm::APSInt *SimpleSValBuilder::getKnownValue(const GRState *state,
+                                                   SVal V) {
+  if (V.isUnknownOrUndef())
+    return NULL;
+
+  if (loc::ConcreteInt* X = dyn_cast<loc::ConcreteInt>(&V))
+    return &X->getValue();
+
+  if (nonloc::ConcreteInt* X = dyn_cast<nonloc::ConcreteInt>(&V))
+    return &X->getValue();
+
+  if (SymbolRef Sym = V.getAsSymbol())
+    return state->getSymVal(Sym);
+
+  // FIXME: Add support for SymExprs.
+  return NULL;
+}
diff --git a/lib/StaticAnalyzer/Store.cpp b/lib/StaticAnalyzer/Store.cpp
new file mode 100644 (file)
index 0000000..f1b8338
--- /dev/null
@@ -0,0 +1,334 @@
+//== Store.cpp - Interface for maps from Locations to 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 defined the types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/Store.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/AST/CharUnits.h"
+
+using namespace clang;
+using namespace ento;
+
+StoreManager::StoreManager(GRStateManager &stateMgr)
+  : svalBuilder(stateMgr.getSValBuilder()), StateMgr(stateMgr),
+    MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {}
+
+Store StoreManager::EnterStackFrame(const GRState *state,
+                                    const StackFrameContext *frame) {
+  return state->getStore();
+}
+
+const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
+                                              QualType EleTy, uint64_t index) {
+  NonLoc idx = svalBuilder.makeArrayIndex(index);
+  return MRMgr.getElementRegion(EleTy, idx, Base, svalBuilder.getContext());
+}
+
+// FIXME: Merge with the implementation of the same method in MemRegion.cpp
+static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
+  if (const RecordType *RT = Ty->getAs<RecordType>()) {
+    const RecordDecl *D = RT->getDecl();
+    if (!D->getDefinition())
+      return false;
+  }
+
+  return true;
+}
+
+const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R, 
+                                                        QualType T) {
+  NonLoc idx = svalBuilder.makeZeroArrayIndex();
+  assert(!T.isNull());
+  return MRMgr.getElementRegion(T, idx, R, Ctx);
+}
+
+const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) {
+
+  ASTContext& Ctx = StateMgr.getContext();
+
+  // Handle casts to Objective-C objects.
+  if (CastToTy->isObjCObjectPointerType())
+    return R->StripCasts();
+
+  if (CastToTy->isBlockPointerType()) {
+    // FIXME: We may need different solutions, depending on the symbol
+    // involved.  Blocks can be casted to/from 'id', as they can be treated
+    // as Objective-C objects.  This could possibly be handled by enhancing
+    // our reasoning of downcasts of symbolic objects.
+    if (isa<CodeTextRegion>(R) || isa<SymbolicRegion>(R))
+      return R;
+
+    // We don't know what to make of it.  Return a NULL region, which
+    // will be interpretted as UnknownVal.
+    return NULL;
+  }
+
+  // Now assume we are casting from pointer to pointer. Other cases should
+  // already be handled.
+  QualType PointeeTy = CastToTy->getAs<PointerType>()->getPointeeType();
+  QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
+
+  // Handle casts to void*.  We just pass the region through.
+  if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy)
+    return R;
+
+  // Handle casts from compatible types.
+  if (R->isBoundable())
+    if (const TypedRegion *TR = dyn_cast<TypedRegion>(R)) {
+      QualType ObjTy = Ctx.getCanonicalType(TR->getValueType());
+      if (CanonPointeeTy == ObjTy)
+        return R;
+    }
+
+  // Process region cast according to the kind of the region being cast.
+  switch (R->getKind()) {
+    case MemRegion::CXXThisRegionKind:
+    case MemRegion::GenericMemSpaceRegionKind:
+    case MemRegion::StackLocalsSpaceRegionKind:
+    case MemRegion::StackArgumentsSpaceRegionKind:
+    case MemRegion::HeapSpaceRegionKind:
+    case MemRegion::UnknownSpaceRegionKind:
+    case MemRegion::NonStaticGlobalSpaceRegionKind:
+    case MemRegion::StaticGlobalSpaceRegionKind: {
+      assert(0 && "Invalid region cast");
+      break;
+    }
+
+    case MemRegion::FunctionTextRegionKind:
+    case MemRegion::BlockTextRegionKind:
+    case MemRegion::BlockDataRegionKind:
+    case MemRegion::StringRegionKind:
+      // FIXME: Need to handle arbitrary downcasts.
+    case MemRegion::SymbolicRegionKind:
+    case MemRegion::AllocaRegionKind:
+    case MemRegion::CompoundLiteralRegionKind:
+    case MemRegion::FieldRegionKind:
+    case MemRegion::ObjCIvarRegionKind:
+    case MemRegion::VarRegionKind:
+    case MemRegion::CXXTempObjectRegionKind:
+    case MemRegion::CXXBaseObjectRegionKind:
+      return MakeElementRegion(R, PointeeTy);
+
+    case MemRegion::ElementRegionKind: {
+      // If we are casting from an ElementRegion to another type, the
+      // algorithm is as follows:
+      //
+      // (1) Compute the "raw offset" of the ElementRegion from the
+      //     base region.  This is done by calling 'getAsRawOffset()'.
+      //
+      // (2a) If we get a 'RegionRawOffset' after calling
+      //      'getAsRawOffset()', determine if the absolute offset
+      //      can be exactly divided into chunks of the size of the
+      //      casted-pointee type.  If so, create a new ElementRegion with
+      //      the pointee-cast type as the new ElementType and the index
+      //      being the offset divded by the chunk size.  If not, create
+      //      a new ElementRegion at offset 0 off the raw offset region.
+      //
+      // (2b) If we don't a get a 'RegionRawOffset' after calling
+      //      'getAsRawOffset()', it means that we are at offset 0.
+      //
+      // FIXME: Handle symbolic raw offsets.
+
+      const ElementRegion *elementR = cast<ElementRegion>(R);
+      const RegionRawOffset &rawOff = elementR->getAsArrayOffset();
+      const MemRegion *baseR = rawOff.getRegion();
+
+      // If we cannot compute a raw offset, throw up our hands and return
+      // a NULL MemRegion*.
+      if (!baseR)
+        return NULL;
+
+      CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset());
+
+      if (off.isZero()) {
+        // Edge case: we are at 0 bytes off the beginning of baseR.  We
+        // check to see if type we are casting to is the same as the base
+        // region.  If so, just return the base region.
+        if (const TypedRegion *TR = dyn_cast<TypedRegion>(baseR)) {
+          QualType ObjTy = Ctx.getCanonicalType(TR->getValueType());
+          QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
+          if (CanonPointeeTy == ObjTy)
+            return baseR;
+        }
+
+        // Otherwise, create a new ElementRegion at offset 0.
+        return MakeElementRegion(baseR, PointeeTy);
+      }
+
+      // We have a non-zero offset from the base region.  We want to determine
+      // if the offset can be evenly divided by sizeof(PointeeTy).  If so,
+      // we create an ElementRegion whose index is that value.  Otherwise, we
+      // create two ElementRegions, one that reflects a raw offset and the other
+      // that reflects the cast.
+
+      // Compute the index for the new ElementRegion.
+      int64_t newIndex = 0;
+      const MemRegion *newSuperR = 0;
+
+      // We can only compute sizeof(PointeeTy) if it is a complete type.
+      if (IsCompleteType(Ctx, PointeeTy)) {
+        // Compute the size in **bytes**.
+        CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
+        if (!pointeeTySize.isZero()) {
+          // Is the offset a multiple of the size?  If so, we can layer the
+          // ElementRegion (with elementType == PointeeTy) directly on top of
+          // the base region.
+          if (off % pointeeTySize == 0) {
+            newIndex = off / pointeeTySize;
+            newSuperR = baseR;
+          }
+        }
+      }
+
+      if (!newSuperR) {
+        // Create an intermediate ElementRegion to represent the raw byte.
+        // This will be the super region of the final ElementRegion.
+        newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity());
+      }
+
+      return MakeElementRegion(newSuperR, PointeeTy, newIndex);
+    }
+  }
+
+  assert(0 && "unreachable");
+  return 0;
+}
+
+
+/// CastRetrievedVal - Used by subclasses of StoreManager to implement
+///  implicit casts that arise from loads from regions that are reinterpreted
+///  as another region.
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+                                    QualType castTy, bool performTestOnly) {
+  
+  if (castTy.isNull())
+    return V;
+  
+  ASTContext &Ctx = svalBuilder.getContext();
+
+  if (performTestOnly) {  
+    // Automatically translate references to pointers.
+    QualType T = R->getValueType();
+    if (const ReferenceType *RT = T->getAs<ReferenceType>())
+      T = Ctx.getPointerType(RT->getPointeeType());
+    
+    assert(svalBuilder.getContext().hasSameUnqualifiedType(castTy, T));
+    return V;
+  }
+  
+  if (const Loc *L = dyn_cast<Loc>(&V))
+    return svalBuilder.evalCastL(*L, castTy);
+  else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
+    return svalBuilder.evalCastNL(*NL, castTy);
+  
+  return V;
+}
+
+SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
+  if (Base.isUnknownOrUndef())
+    return Base;
+
+  Loc BaseL = cast<Loc>(Base);
+  const MemRegion* BaseR = 0;
+
+  switch (BaseL.getSubKind()) {
+  case loc::MemRegionKind:
+    BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+    break;
+
+  case loc::GotoLabelKind:
+    // These are anormal cases. Flag an undefined value.
+    return UndefinedVal();
+
+  case loc::ConcreteIntKind:
+    // While these seem funny, this can happen through casts.
+    // FIXME: What we should return is the field offset.  For example,
+    //  add the field offset to the integer value.  That way funny things
+    //  like this work properly:  &(((struct foo *) 0xa)->f)
+    return Base;
+
+  default:
+    assert(0 && "Unhandled Base.");
+    return Base;
+  }
+
+  // NOTE: We must have this check first because ObjCIvarDecl is a subclass
+  // of FieldDecl.
+  if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
+    return loc::MemRegionVal(MRMgr.getObjCIvarRegion(ID, BaseR));
+
+  return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
+}
+
+SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, 
+                                    SVal Base) {
+
+  // If the base is an unknown or undefined value, just return it back.
+  // FIXME: For absolute pointer addresses, we just return that value back as
+  //  well, although in reality we should return the offset added to that
+  //  value.
+  if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+    return Base;
+
+  const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
+
+  // Pointer of any type can be cast and used as array base.
+  const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
+
+  // Convert the offset to the appropriate size and signedness.
+  Offset = cast<NonLoc>(svalBuilder.convertToArrayIndex(Offset));
+
+  if (!ElemR) {
+    //
+    // If the base region is not an ElementRegion, create one.
+    // This can happen in the following example:
+    //
+    //   char *p = __builtin_alloc(10);
+    //   p[1] = 8;
+    //
+    //  Observe that 'p' binds to an AllocaRegion.
+    //
+    return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
+                                                    BaseRegion, Ctx));
+  }
+
+  SVal BaseIdx = ElemR->getIndex();
+
+  if (!isa<nonloc::ConcreteInt>(BaseIdx))
+    return UnknownVal();
+
+  const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
+
+  // Only allow non-integer offsets if the base region has no offset itself.
+  // FIXME: This is a somewhat arbitrary restriction. We should be using
+  // SValBuilder here to add the two offsets without checking their types.
+  if (!isa<nonloc::ConcreteInt>(Offset)) {
+    if (isa<ElementRegion>(BaseRegion->StripCasts()))
+      return UnknownVal();
+
+    return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
+                                                    ElemR->getSuperRegion(),
+                                                    Ctx));
+  }
+
+  const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
+  assert(BaseIdxI.isSigned());
+
+  // Compute the new index.
+  nonloc::ConcreteInt NewIdx(svalBuilder.getBasicValueFactory().getValue(BaseIdxI +
+                                                                    OffI));
+
+  // Construct the new ElementRegion.
+  const MemRegion *ArrayR = ElemR->getSuperRegion();
+  return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
+                                                  Ctx));
+}
diff --git a/lib/StaticAnalyzer/SymbolManager.cpp b/lib/StaticAnalyzer/SymbolManager.cpp
new file mode 100644 (file)
index 0000000..08677da
--- /dev/null
@@ -0,0 +1,343 @@
+//== SymbolManager.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 SymbolManager, a class that manages symbolic values
+//  created for use by ExprEngine and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+void SymExpr::dump() const {
+  dumpToStream(llvm::errs());
+}
+
+static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) {
+  switch (Op) {
+    default:
+      assert(false && "operator printing not implemented");
+      break;
+    case BO_Mul: os << '*'  ; break;
+    case BO_Div: os << '/'  ; break;
+    case BO_Rem: os << '%'  ; break;
+    case BO_Add: os << '+'  ; break;
+    case BO_Sub: os << '-'  ; break;
+    case BO_Shl: os << "<<" ; break;
+    case BO_Shr: os << ">>" ; break;
+    case BO_LT:  os << "<"  ; break;
+    case BO_GT:  os << '>'  ; break;
+    case BO_LE:  os << "<=" ; break;
+    case BO_GE:  os << ">=" ; break;
+    case BO_EQ:  os << "==" ; break;
+    case BO_NE:  os << "!=" ; break;
+    case BO_And: os << '&'  ; break;
+    case BO_Xor: os << '^'  ; break;
+    case BO_Or:  os << '|'  ; break;
+  }
+}
+
+void SymIntExpr::dumpToStream(llvm::raw_ostream& os) const {
+  os << '(';
+  getLHS()->dumpToStream(os);
+  os << ") ";
+  print(os, getOpcode());
+  os << ' ' << getRHS().getZExtValue();
+  if (getRHS().isUnsigned()) os << 'U';
+}
+
+void SymSymExpr::dumpToStream(llvm::raw_ostream& os) const {
+  os << '(';
+  getLHS()->dumpToStream(os);
+  os << ") ";
+  os << '(';
+  getRHS()->dumpToStream(os);
+  os << ')';
+}
+
+void SymbolConjured::dumpToStream(llvm::raw_ostream& os) const {
+  os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
+}
+
+void SymbolDerived::dumpToStream(llvm::raw_ostream& os) const {
+  os << "derived_$" << getSymbolID() << '{'
+     << getParentSymbol() << ',' << getRegion() << '}';
+}
+
+void SymbolExtent::dumpToStream(llvm::raw_ostream& os) const {
+  os << "extent_$" << getSymbolID() << '{' << getRegion() << '}';
+}
+
+void SymbolMetadata::dumpToStream(llvm::raw_ostream& os) const {
+  os << "meta_$" << getSymbolID() << '{'
+     << getRegion() << ',' << T.getAsString() << '}';
+}
+
+void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const {
+  os << "reg_$" << getSymbolID() << "<" << R << ">";
+}
+
+const SymbolRegionValue*
+SymbolManager::getRegionValueSymbol(const TypedRegion* R) {
+  llvm::FoldingSetNodeID profile;
+  SymbolRegionValue::Profile(profile, R);
+  void* InsertPos;
+  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+  if (!SD) {
+    SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
+    new (SD) SymbolRegionValue(SymbolCounter, R);
+    DataSet.InsertNode(SD, InsertPos);
+    ++SymbolCounter;
+  }
+
+  return cast<SymbolRegionValue>(SD);
+}
+
+const SymbolConjured*
+SymbolManager::getConjuredSymbol(const Stmt* E, QualType T, unsigned Count,
+                                 const void* SymbolTag) {
+
+  llvm::FoldingSetNodeID profile;
+  SymbolConjured::Profile(profile, E, T, Count, SymbolTag);
+  void* InsertPos;
+  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+  if (!SD) {
+    SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
+    new (SD) SymbolConjured(SymbolCounter, E, T, Count, SymbolTag);
+    DataSet.InsertNode(SD, InsertPos);
+    ++SymbolCounter;
+  }
+
+  return cast<SymbolConjured>(SD);
+}
+
+const SymbolDerived*
+SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
+                                const TypedRegion *R) {
+
+  llvm::FoldingSetNodeID profile;
+  SymbolDerived::Profile(profile, parentSymbol, R);
+  void* InsertPos;
+  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+  if (!SD) {
+    SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
+    new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
+    DataSet.InsertNode(SD, InsertPos);
+    ++SymbolCounter;
+  }
+
+  return cast<SymbolDerived>(SD);
+}
+
+const SymbolExtent*
+SymbolManager::getExtentSymbol(const SubRegion *R) {
+  llvm::FoldingSetNodeID profile;
+  SymbolExtent::Profile(profile, R);
+  void* InsertPos;
+  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+  if (!SD) {
+    SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
+    new (SD) SymbolExtent(SymbolCounter, R);
+    DataSet.InsertNode(SD, InsertPos);
+    ++SymbolCounter;
+  }
+
+  return cast<SymbolExtent>(SD);
+}
+
+const SymbolMetadata*
+SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt* S, QualType T,
+                                 unsigned Count, const void* SymbolTag) {
+
+  llvm::FoldingSetNodeID profile;
+  SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag);
+  void* InsertPos;
+  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
+  if (!SD) {
+    SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
+    new (SD) SymbolMetadata(SymbolCounter, R, S, T, Count, SymbolTag);
+    DataSet.InsertNode(SD, InsertPos);
+    ++SymbolCounter;
+  }
+
+  return cast<SymbolMetadata>(SD);
+}
+
+const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
+                                               BinaryOperator::Opcode op,
+                                               const llvm::APSInt& v,
+                                               QualType t) {
+  llvm::FoldingSetNodeID ID;
+  SymIntExpr::Profile(ID, lhs, op, v, t);
+  void *InsertPos;
+  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!data) {
+    data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
+    new (data) SymIntExpr(lhs, op, v, t);
+    DataSet.InsertNode(data, InsertPos);
+  }
+
+  return cast<SymIntExpr>(data);
+}
+
+const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
+                                               BinaryOperator::Opcode op,
+                                               const SymExpr *rhs,
+                                               QualType t) {
+  llvm::FoldingSetNodeID ID;
+  SymSymExpr::Profile(ID, lhs, op, rhs, t);
+  void *InsertPos;
+  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (!data) {
+    data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
+    new (data) SymSymExpr(lhs, op, rhs, t);
+    DataSet.InsertNode(data, InsertPos);
+  }
+
+  return cast<SymSymExpr>(data);
+}
+
+QualType SymbolConjured::getType(ASTContext&) const {
+  return T;
+}
+
+QualType SymbolDerived::getType(ASTContext& Ctx) const {
+  return R->getValueType();
+}
+
+QualType SymbolExtent::getType(ASTContext& Ctx) const {
+  return Ctx.getSizeType();
+}
+
+QualType SymbolMetadata::getType(ASTContext&) const {
+  return T;
+}
+
+QualType SymbolRegionValue::getType(ASTContext& C) const {
+  return R->getValueType();
+}
+
+SymbolManager::~SymbolManager() {}
+
+bool SymbolManager::canSymbolicate(QualType T) {
+  if (Loc::IsLocType(T))
+    return true;
+
+  if (T->isIntegerType())
+    return T->isScalarType();
+
+  if (T->isRecordType())
+    return true;
+
+  return false;
+}
+
+void SymbolReaper::markLive(SymbolRef sym) {
+  TheLiving.insert(sym);
+  TheDead.erase(sym);
+}
+
+void SymbolReaper::markInUse(SymbolRef sym) {
+  if (isa<SymbolMetadata>(sym))
+    MetadataInUse.insert(sym);
+}
+
+bool SymbolReaper::maybeDead(SymbolRef sym) {
+  if (isLive(sym))
+    return false;
+
+  TheDead.insert(sym);
+  return true;
+}
+
+static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) {
+  MR = MR->getBaseRegion();
+
+  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+    return Reaper.isLive(SR->getSymbol());
+
+  if (const VarRegion *VR = dyn_cast<VarRegion>(MR))
+    return Reaper.isLive(VR);
+
+  // FIXME: This is a gross over-approximation. What we really need is a way to
+  // tell if anything still refers to this region. Unlike SymbolicRegions,
+  // AllocaRegions don't have associated symbols, though, so we don't actually
+  // have a way to track their liveness.
+  if (isa<AllocaRegion>(MR))
+    return true;
+
+  if (isa<CXXThisRegion>(MR))
+    return true;
+
+  if (isa<MemSpaceRegion>(MR))
+    return true;
+
+  return false;
+}
+
+bool SymbolReaper::isLive(SymbolRef sym) {
+  if (TheLiving.count(sym))
+    return true;
+
+  if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) {
+    if (isLive(derived->getParentSymbol())) {
+      markLive(sym);
+      return true;
+    }
+    return false;
+  }
+
+  if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) {
+    if (IsLiveRegion(*this, extent->getRegion())) {
+      markLive(sym);
+      return true;
+    }
+    return false;
+  }
+
+  if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) {
+    if (MetadataInUse.count(sym)) {
+      if (IsLiveRegion(*this, metadata->getRegion())) {
+        markLive(sym);
+        MetadataInUse.erase(sym);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Interogate the symbol.  It may derive from an input value to
+  // the analyzed function/method.
+  return isa<SymbolRegionValue>(sym);
+}
+
+bool SymbolReaper::isLive(const Stmt* ExprVal) const {
+  return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
+      isLive(Loc, ExprVal);
+}
+
+bool SymbolReaper::isLive(const VarRegion *VR) const {
+  const StackFrameContext *VarContext = VR->getStackFrame();
+  const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame();
+
+  if (VarContext == CurrentContext)
+    return LCtx->getAnalysisContext()->getRelaxedLiveVariables()->
+        isLive(Loc, VR->getDecl());
+
+  return VarContext->isParentOf(CurrentContext);
+}
+
+SymbolVisitor::~SymbolVisitor() {}
diff --git a/lib/StaticAnalyzer/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/TextPathDiagnostics.cpp
new file mode 100644 (file)
index 0000000..9ca378f
--- /dev/null
@@ -0,0 +1,70 @@
+//===--- TextPathDiagnostics.cpp - Text Diagnostics for Paths ---*- 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 TextPathDiagnostics object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
+#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace ento;
+using namespace llvm;
+
+namespace {
+
+/// \brief Simple path diagnostic client used for outputting as diagnostic notes
+/// the sequence of events.
+class TextPathDiagnostics : public PathDiagnosticClient {
+  const std::string OutputFile;
+  Diagnostic &Diag;
+
+public:
+  TextPathDiagnostics(const std::string& output, Diagnostic &diag)
+    : OutputFile(output), Diag(diag) {}
+
+  void HandlePathDiagnostic(const PathDiagnostic* D);
+
+  void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) { }
+  
+  virtual llvm::StringRef getName() const {
+    return "TextPathDiagnostics";
+  }
+
+  PathGenerationScheme getGenerationScheme() const { return Minimal; }
+  bool supportsLogicalOpControlFlow() const { return true; }
+  bool supportsAllBlockEdges() const { return true; }
+  virtual bool useVerboseDescription() const { return true; }
+};
+
+} // end anonymous namespace
+
+PathDiagnosticClient*
+ento::createTextPathDiagnosticClient(const std::string& out,
+                                     const Preprocessor &PP) {
+  return new TextPathDiagnostics(out, PP.getDiagnostics());
+}
+
+void TextPathDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+  if (!D)
+    return;
+
+  if (D->empty()) {
+    delete D;
+    return;
+  }
+
+  for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) {
+    unsigned diagID = Diag.getDiagnosticIDs()->getCustomDiagID(
+                                           DiagnosticIDs::Note, I->getString());
+    Diag.Report(I->getLocation().asLocation(), diagID);
+  }
+}
index 6e02e85e5a51509499755fa7c562fbea4546df96..14c06c098fc1234f70805f4d2e62cf181f667fd9 100644 (file)
@@ -8,8 +8,8 @@ set( LLVM_USED_LIBS
   clangCodeGen
   clangParse
   clangSema
-  clangEntoCheckers
-  clangEntoCore
+  clangStaticAnalyzerCheckers
+  clangStaticAnalyzerCore
   clangAnalysis
   clangIndex
   clangRewrite
index e97bfeb44358c80f4bf63176f63e44b6b1a528c2..9942310e4ff22e92eda0ef09c0a0128f511f7fc5 100644 (file)
@@ -39,7 +39,7 @@ LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
                    ipo selectiondag
 USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
            clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
-           clangEntoCheckers.a clangEntoCore.a clangAnalysis.a clangIndex.a clangRewrite.a \
+           clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangAnalysis.a clangIndex.a clangRewrite.a \
            clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile