[cfe-commits] r122422 - in /cfe/trunk: examples/PrintFunctionNames/ examples/clang-interpreter/ examples/wpa/ lib/FrontendTool/ lib/GR/ lib/GR/Checkers/ tools/driver/
Argyrios Kyrtzidis
akyrtzi at gmail.com
Wed Dec 22 10:52:57 PST 2010
Author: akirtzidis
Date: Wed Dec 22 12:52:56 2010
New Revision: 122422
URL: http://llvm.org/viewvc/llvm-project?rev=122422&view=rev
Log:
[analyzer] Refactoring: Move checkers into lib/GR/Checkers and their own library, libclangGRCheckers
Added:
cfe/trunk/lib/GR/Checkers/
cfe/trunk/lib/GR/Checkers/AdjustedReturnValueChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp
cfe/trunk/lib/GR/Checkers/ArrayBoundChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/ArrayBoundChecker.cpp
cfe/trunk/lib/GR/Checkers/AttrNonNullChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/AttrNonNullChecker.cpp
cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp
cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.h
- copied, changed from r122421, cfe/trunk/lib/GR/BasicObjCFoundationChecks.h
cfe/trunk/lib/GR/Checkers/BuiltinFunctionChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp
cfe/trunk/lib/GR/Checkers/CMakeLists.txt
cfe/trunk/lib/GR/Checkers/CStringChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CStringChecker.cpp
cfe/trunk/lib/GR/Checkers/CallAndMessageChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CallAndMessageChecker.cpp
cfe/trunk/lib/GR/Checkers/CastSizeChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CastSizeChecker.cpp
cfe/trunk/lib/GR/Checkers/CastToStructChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CastToStructChecker.cpp
cfe/trunk/lib/GR/Checkers/CheckDeadStores.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CheckDeadStores.cpp
cfe/trunk/lib/GR/Checkers/CheckObjCDealloc.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CheckObjCDealloc.cpp
cfe/trunk/lib/GR/Checkers/CheckObjCInstMethSignature.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp
cfe/trunk/lib/GR/Checkers/CheckSecuritySyntaxOnly.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp
cfe/trunk/lib/GR/Checkers/CheckSizeofPointer.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/CheckSizeofPointer.cpp
cfe/trunk/lib/GR/Checkers/ChrootChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/ChrootChecker.cpp
cfe/trunk/lib/GR/Checkers/DereferenceChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/DereferenceChecker.cpp
cfe/trunk/lib/GR/Checkers/DivZeroChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/DivZeroChecker.cpp
cfe/trunk/lib/GR/Checkers/FixedAddressChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/FixedAddressChecker.cpp
cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp
cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.h
- copied, changed from r122421, cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h
cfe/trunk/lib/GR/Checkers/GRExprEngineInternalChecks.h
- copied, changed from r122421, cfe/trunk/lib/GR/GRExprEngineInternalChecks.h
cfe/trunk/lib/GR/Checkers/IdempotentOperationChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/IdempotentOperationChecker.cpp
cfe/trunk/lib/GR/Checkers/LLVMConventionsChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/LLVMConventionsChecker.cpp
cfe/trunk/lib/GR/Checkers/MacOSXAPIChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/MacOSXAPIChecker.cpp
cfe/trunk/lib/GR/Checkers/Makefile
- copied, changed from r122421, cfe/trunk/lib/GR/Makefile
cfe/trunk/lib/GR/Checkers/MallocChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/MallocChecker.cpp
cfe/trunk/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp
cfe/trunk/lib/GR/Checkers/NSErrorChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/NSErrorChecker.cpp
cfe/trunk/lib/GR/Checkers/NoReturnFunctionChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp
cfe/trunk/lib/GR/Checkers/OSAtomicChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/OSAtomicChecker.cpp
cfe/trunk/lib/GR/Checkers/ObjCAtSyncChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp
cfe/trunk/lib/GR/Checkers/ObjCUnusedIVarsChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp
cfe/trunk/lib/GR/Checkers/PointerArithChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/PointerArithChecker.cpp
cfe/trunk/lib/GR/Checkers/PointerSubChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/PointerSubChecker.cpp
cfe/trunk/lib/GR/Checkers/PthreadLockChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/PthreadLockChecker.cpp
cfe/trunk/lib/GR/Checkers/ReturnPointerRangeChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp
cfe/trunk/lib/GR/Checkers/ReturnUndefChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/ReturnUndefChecker.cpp
cfe/trunk/lib/GR/Checkers/StackAddrLeakChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/StackAddrLeakChecker.cpp
cfe/trunk/lib/GR/Checkers/StreamChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/StreamChecker.cpp
cfe/trunk/lib/GR/Checkers/UndefBranchChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UndefBranchChecker.cpp
cfe/trunk/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp
cfe/trunk/lib/GR/Checkers/UndefResultChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UndefResultChecker.cpp
cfe/trunk/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp
cfe/trunk/lib/GR/Checkers/UndefinedAssignmentChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp
cfe/trunk/lib/GR/Checkers/UnixAPIChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UnixAPIChecker.cpp
cfe/trunk/lib/GR/Checkers/UnreachableCodeChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/UnreachableCodeChecker.cpp
cfe/trunk/lib/GR/Checkers/VLASizeChecker.cpp
- copied, changed from r122421, cfe/trunk/lib/GR/VLASizeChecker.cpp
Removed:
cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp
cfe/trunk/lib/GR/ArrayBoundChecker.cpp
cfe/trunk/lib/GR/AttrNonNullChecker.cpp
cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp
cfe/trunk/lib/GR/BasicObjCFoundationChecks.h
cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp
cfe/trunk/lib/GR/CStringChecker.cpp
cfe/trunk/lib/GR/CallAndMessageChecker.cpp
cfe/trunk/lib/GR/CastSizeChecker.cpp
cfe/trunk/lib/GR/CastToStructChecker.cpp
cfe/trunk/lib/GR/CheckDeadStores.cpp
cfe/trunk/lib/GR/CheckObjCDealloc.cpp
cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp
cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp
cfe/trunk/lib/GR/CheckSizeofPointer.cpp
cfe/trunk/lib/GR/ChrootChecker.cpp
cfe/trunk/lib/GR/DereferenceChecker.cpp
cfe/trunk/lib/GR/DivZeroChecker.cpp
cfe/trunk/lib/GR/FixedAddressChecker.cpp
cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp
cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h
cfe/trunk/lib/GR/GRExprEngineInternalChecks.h
cfe/trunk/lib/GR/IdempotentOperationChecker.cpp
cfe/trunk/lib/GR/LLVMConventionsChecker.cpp
cfe/trunk/lib/GR/MacOSXAPIChecker.cpp
cfe/trunk/lib/GR/MallocChecker.cpp
cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp
cfe/trunk/lib/GR/NSErrorChecker.cpp
cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp
cfe/trunk/lib/GR/OSAtomicChecker.cpp
cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp
cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp
cfe/trunk/lib/GR/PointerArithChecker.cpp
cfe/trunk/lib/GR/PointerSubChecker.cpp
cfe/trunk/lib/GR/PthreadLockChecker.cpp
cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp
cfe/trunk/lib/GR/ReturnUndefChecker.cpp
cfe/trunk/lib/GR/StackAddrLeakChecker.cpp
cfe/trunk/lib/GR/StreamChecker.cpp
cfe/trunk/lib/GR/UndefBranchChecker.cpp
cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp
cfe/trunk/lib/GR/UndefResultChecker.cpp
cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp
cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp
cfe/trunk/lib/GR/UnixAPIChecker.cpp
cfe/trunk/lib/GR/UnreachableCodeChecker.cpp
cfe/trunk/lib/GR/VLASizeChecker.cpp
Modified:
cfe/trunk/examples/PrintFunctionNames/CMakeLists.txt
cfe/trunk/examples/clang-interpreter/CMakeLists.txt
cfe/trunk/examples/clang-interpreter/Makefile
cfe/trunk/examples/wpa/CMakeLists.txt
cfe/trunk/examples/wpa/Makefile
cfe/trunk/lib/FrontendTool/CMakeLists.txt
cfe/trunk/lib/GR/AnalysisConsumer.cpp
cfe/trunk/lib/GR/AnalyzerStatsChecker.cpp
cfe/trunk/lib/GR/CMakeLists.txt
cfe/trunk/lib/GR/GRExprEngine.cpp
cfe/trunk/lib/GR/Makefile
cfe/trunk/tools/driver/CMakeLists.txt
cfe/trunk/tools/driver/Makefile
Modified: cfe/trunk/examples/PrintFunctionNames/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/CMakeLists.txt?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/examples/PrintFunctionNames/CMakeLists.txt (original)
+++ cfe/trunk/examples/PrintFunctionNames/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -10,6 +10,7 @@
clangCodeGen
clangParse
clangSema
+ clangGRCheckers
clangGRCore
clangAnalysis
clangIndex
Modified: cfe/trunk/examples/clang-interpreter/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/CMakeLists.txt?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/examples/clang-interpreter/CMakeLists.txt (original)
+++ cfe/trunk/examples/clang-interpreter/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -6,6 +6,7 @@
clangDriver
clangCodeGen
clangSema
+ clangGRCheckers
clangGRCore
clangIndex
clangAnalysis
Modified: cfe/trunk/examples/clang-interpreter/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/Makefile?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/examples/clang-interpreter/Makefile (original)
+++ cfe/trunk/examples/clang-interpreter/Makefile Wed Dec 22 12:52:56 2010
@@ -18,7 +18,7 @@
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
selectiondag asmparser
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
- clangSema.a clangGRCore.a clangAnalysis.a clangRewrite.a \
+ clangSema.a clangGRCheckers.a clangGRCore.a clangAnalysis.a clangRewrite.a \
clangAST.a clangParse.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
Modified: cfe/trunk/examples/wpa/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/wpa/CMakeLists.txt?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/examples/wpa/CMakeLists.txt (original)
+++ cfe/trunk/examples/wpa/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -7,6 +7,7 @@
clangSema
clangAnalysis
clangSerialization
+ clangGRCheckers
clangGRCore
clangRewrite
clangAST
Modified: cfe/trunk/examples/wpa/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/wpa/Makefile?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/examples/wpa/Makefile (original)
+++ cfe/trunk/examples/wpa/Makefile Wed Dec 22 12:52:56 2010
@@ -16,7 +16,7 @@
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := asmparser bitreader mc core
-USEDLIBS = clangGRCore.a clangIndex.a clangFrontend.a clangDriver.a \
+USEDLIBS = clangGRCheckers.a clangGRCore.a clangIndex.a clangFrontend.a clangDriver.a \
clangSema.a clangAnalysis.a clangSerialization.a \
clangAST.a clangParse.a clangLex.a clangBasic.a
Modified: cfe/trunk/lib/FrontendTool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/FrontendTool/CMakeLists.txt?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/lib/FrontendTool/CMakeLists.txt (original)
+++ cfe/trunk/lib/FrontendTool/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -1,7 +1,7 @@
set(LLVM_NO_RTTI 1)
set(LLVM_USED_LIBS clangDriver clangFrontend clangRewrite clangCodeGen
- clangGRCore)
+ clangGRCheckers clangGRCore)
add_clang_library(clangFrontendTool
ExecuteCompilerInvocation.cpp
Removed: cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp (original)
+++ cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp (removed)
@@ -1,95 +0,0 @@
-//== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugReporter.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterAdjustedReturnValueChecker(GRExprEngine &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));
- }
-}
Modified: cfe/trunk/lib/GR/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/AnalysisConsumer.cpp?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/lib/GR/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/GR/AnalysisConsumer.cpp Wed Dec 22 12:52:56 2010
@@ -28,8 +28,11 @@
#include "clang/GR/PathSensitive/GRExprEngine.h"
#include "clang/GR/PathSensitive/GRTransferFuncs.h"
#include "clang/GR/PathDiagnosticClients.h"
-#include "GRExprEngineExperimentalChecks.h"
-#include "GRExprEngineInternalChecks.h"
+
+// FIXME: Restructure checker registration.
+#include "Checkers/GRExprEngineExperimentalChecks.h"
+#include "Checkers/GRExprEngineInternalChecks.h"
+
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/AnalyzerOptions.h"
Modified: cfe/trunk/lib/GR/AnalyzerStatsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/AnalyzerStatsChecker.cpp?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/lib/GR/AnalyzerStatsChecker.cpp (original)
+++ cfe/trunk/lib/GR/AnalyzerStatsChecker.cpp Wed Dec 22 12:52:56 2010
@@ -12,7 +12,10 @@
#include "clang/GR/PathSensitive/CheckerVisitor.h"
#include "clang/GR/PathSensitive/ExplodedGraph.h"
#include "clang/GR/BugReporter/BugReporter.h"
-#include "GRExprEngineExperimentalChecks.h"
+
+// FIXME: Restructure checker registration.
+#include "Checkers/GRExprEngineExperimentalChecks.h"
+
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
Removed: cfe/trunk/lib/GR/ArrayBoundChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/ArrayBoundChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/ArrayBoundChecker.cpp (original)
+++ cfe/trunk/lib/GR/ArrayBoundChecker.cpp (removed)
@@ -1,90 +0,0 @@
-//== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-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 clang::RegisterArrayBoundChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/AttrNonNullChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/AttrNonNullChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/AttrNonNullChecker.cpp (original)
+++ cfe/trunk/lib/GR/AttrNonNullChecker.cpp (removed)
@@ -1,135 +0,0 @@
-//===--- 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 GRExprEngine that
-// performs checks for arguments declared to have nonnull attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterAttrNonNullChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp (original)
+++ cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp (removed)
@@ -1,520 +0,0 @@
-//== 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/GR/PathSensitive/ExplodedGraph.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-#include "clang/GR/PathSensitive/GRState.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/MemRegion.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/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;
-
-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 clang::RegisterAppleChecks(GRExprEngine& 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());
-}
Removed: cfe/trunk/lib/GR/BasicObjCFoundationChecks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/BasicObjCFoundationChecks.h?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/BasicObjCFoundationChecks.h (original)
+++ cfe/trunk/lib/GR/BasicObjCFoundationChecks.h (removed)
@@ -1,31 +0,0 @@
-//== 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_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
-#define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
-
-namespace clang {
-
-class ASTContext;
-class BugReporter;
-class Decl;
-class GRExprEngine;
-
-void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D);
-void RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng);
-
-} // end clang namespace
-
-#endif
Removed: cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp (original)
+++ cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp (removed)
@@ -1,82 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/PathSensitive/Checker.h"
-#include "clang/Basic/Builtins.h"
-
-using namespace clang;
-
-namespace {
-
-class BuiltinFunctionChecker : public Checker {
-public:
- static void *getTag() { static int tag = 0; return &tag; }
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-
-}
-
-void clang::RegisterBuiltinFunctionChecker(GRExprEngine &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;
-}
Modified: cfe/trunk/lib/GR/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CMakeLists.txt?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/lib/GR/CMakeLists.txt (original)
+++ cfe/trunk/lib/GR/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -3,85 +3,41 @@
set(LLVM_USED_LIBS clangBasic clangLex clangAST clangFrontend clangRewrite)
add_clang_library(clangGRCore
- AdjustedReturnValueChecker.cpp
AggExprVisitor.cpp
AnalysisConsumer.cpp
AnalysisManager.cpp
AnalyzerStatsChecker.cpp
- ArrayBoundChecker.cpp
- AttrNonNullChecker.cpp
BasicConstraintManager.cpp
- BasicObjCFoundationChecks.cpp
BasicStore.cpp
BasicValueFactory.cpp
BugReporter.cpp
BugReporterVisitors.cpp
- BuiltinFunctionChecker.cpp
CFRefCount.cpp
- CStringChecker.cpp
- CallAndMessageChecker.cpp
- CastSizeChecker.cpp
- CastToStructChecker.cpp
- CheckDeadStores.cpp
- CheckObjCDealloc.cpp
- CheckObjCInstMethSignature.cpp
- CheckSecuritySyntaxOnly.cpp
- CheckSizeofPointer.cpp
Checker.cpp
CheckerHelpers.cpp
- ChrootChecker.cpp
- DereferenceChecker.cpp
- DivZeroChecker.cpp
Environment.cpp
ExplodedGraph.cpp
- FixedAddressChecker.cpp
FlatStore.cpp
FrontendActions.cpp
GRBlockCounter.cpp
GRCXXExprEngine.cpp
GRCoreEngine.cpp
GRExprEngine.cpp
- GRExprEngineExperimentalChecks.cpp
GRState.cpp
HTMLDiagnostics.cpp
- IdempotentOperationChecker.cpp
- LLVMConventionsChecker.cpp
- MacOSXAPIChecker.cpp
- MallocChecker.cpp
ManagerRegistry.cpp
MemRegion.cpp
- NSAutoreleasePoolChecker.cpp
- NSErrorChecker.cpp
- NoReturnFunctionChecker.cpp
- OSAtomicChecker.cpp
- ObjCAtSyncChecker.cpp
- ObjCUnusedIVarsChecker.cpp
PathDiagnostic.cpp
PlistDiagnostics.cpp
- PointerArithChecker.cpp
- PointerSubChecker.cpp
- PthreadLockChecker.cpp
RangeConstraintManager.cpp
RegionStore.cpp
- ReturnPointerRangeChecker.cpp
- ReturnUndefChecker.cpp
- SValBuilder.cpp
- SVals.cpp
SimpleConstraintManager.cpp
SimpleSValBuilder.cpp
- StackAddrLeakChecker.cpp
Store.cpp
- StreamChecker.cpp
+ SValBuilder.cpp
+ SVals.cpp
SymbolManager.cpp
TextPathDiagnostics.cpp
- UndefBranchChecker.cpp
- UndefCapturedBlockVarChecker.cpp
- UndefResultChecker.cpp
- UndefinedArraySubscriptChecker.cpp
- UndefinedAssignmentChecker.cpp
- UnixAPIChecker.cpp
- UnreachableCodeChecker.cpp
- VLASizeChecker.cpp
)
add_dependencies(clangGRCore ClangAttrClasses ClangAttrList ClangDeclNodes
Removed: cfe/trunk/lib/GR/CStringChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CStringChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CStringChecker.cpp (original)
+++ cfe/trunk/lib/GR/CStringChecker.cpp (removed)
@@ -1,1045 +0,0 @@
-//= 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 "GRExprEngineExperimentalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRStateTrait.h"
-#include "llvm/ADT/StringSwitch.h"
-
-using namespace clang;
-
-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 {
- template <>
- struct GRStateTrait<CStringLength>
- : public GRStatePartialTrait<CStringLength::EntryMap> {
- static void *GDMIndex() { return CStringChecker::getTag(); }
- };
-}
-
-void clang::RegisterCStringChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/CallAndMessageChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CallAndMessageChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CallAndMessageChecker.cpp (original)
+++ cfe/trunk/lib/GR/CallAndMessageChecker.cpp (removed)
@@ -1,349 +0,0 @@
-//===--- 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 "GRExprEngineInternalChecks.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterCallAndMessageChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/CastSizeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CastSizeChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CastSizeChecker.cpp (original)
+++ cfe/trunk/lib/GR/CastSizeChecker.cpp (removed)
@@ -1,90 +0,0 @@
-//=== 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/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-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 clang::RegisterCastSizeChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new CastSizeChecker());
-}
Removed: cfe/trunk/lib/GR/CastToStructChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CastToStructChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CastToStructChecker.cpp (original)
+++ cfe/trunk/lib/GR/CastToStructChecker.cpp (removed)
@@ -1,78 +0,0 @@
-//=== 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/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-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 clang::RegisterCastToStructChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new CastToStructChecker());
-}
Removed: cfe/trunk/lib/GR/CheckDeadStores.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CheckDeadStores.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CheckDeadStores.cpp (original)
+++ cfe/trunk/lib/GR/CheckDeadStores.cpp (removed)
@@ -1,289 +0,0 @@
-//==- 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/GR/Checkers/LocalCheckers.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/GR/BugReporter/BugReporter.h"
-#include "clang/GR/PathSensitive/GRExprEngine.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;
-
-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 clang::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);
-}
Removed: cfe/trunk/lib/GR/CheckObjCDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CheckObjCDealloc.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CheckObjCDealloc.cpp (original)
+++ cfe/trunk/lib/GR/CheckObjCDealloc.cpp (removed)
@@ -1,261 +0,0 @@
-//==- 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/GR/Checkers/LocalCheckers.h"
-#include "clang/GR/BugReporter/PathDiagnostic.h"
-#include "clang/GR/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;
-
-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 clang::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());
- }
- }
-}
-
Removed: cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp (original)
+++ cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp (removed)
@@ -1,119 +0,0 @@
-//=- 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/GR/Checkers/LocalCheckers.h"
-#include "clang/GR/BugReporter/PathDiagnostic.h"
-#include "clang/GR/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;
-
-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 clang::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();
- }
-}
Removed: cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp (original)
+++ cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp (removed)
@@ -1,502 +0,0 @@
-//==- 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/GR/BugReporter/BugReporter.h"
-#include "clang/GR/Checkers/LocalCheckers.h"
-#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-
-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 clang::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
- WalkAST walker(BR);
- walker.Visit(D->getBody());
-}
Removed: cfe/trunk/lib/GR/CheckSizeofPointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/CheckSizeofPointer.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/CheckSizeofPointer.cpp (original)
+++ cfe/trunk/lib/GR/CheckSizeofPointer.cpp (removed)
@@ -1,71 +0,0 @@
-//==- 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/GR/BugReporter/BugReporter.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/GR/Checkers/LocalCheckers.h"
-
-using namespace clang;
-
-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 clang::CheckSizeofPointer(const Decl *D, BugReporter &BR) {
- WalkAST walker(BR);
- walker.Visit(D->getBody());
-}
Copied: cfe/trunk/lib/GR/Checkers/AdjustedReturnValueChecker.cpp (from r122421, cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/AdjustedReturnValueChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/AdjustedReturnValueChecker.cpp&p1=cfe/trunk/lib/GR/AdjustedReturnValueChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/ArrayBoundChecker.cpp (from r122421, cfe/trunk/lib/GR/ArrayBoundChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/ArrayBoundChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/ArrayBoundChecker.cpp&p1=cfe/trunk/lib/GR/ArrayBoundChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/AttrNonNullChecker.cpp (from r122421, cfe/trunk/lib/GR/AttrNonNullChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/AttrNonNullChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/AttrNonNullChecker.cpp&p1=cfe/trunk/lib/GR/AttrNonNullChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.cpp (from r122421, cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.cpp?p2=cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.cpp&p1=cfe/trunk/lib/GR/BasicObjCFoundationChecks.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.h (from r122421, cfe/trunk/lib/GR/BasicObjCFoundationChecks.h)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.h?p2=cfe/trunk/lib/GR/Checkers/BasicObjCFoundationChecks.h&p1=cfe/trunk/lib/GR/BasicObjCFoundationChecks.h&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/BuiltinFunctionChecker.cpp (from r122421, cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/BuiltinFunctionChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/BuiltinFunctionChecker.cpp&p1=cfe/trunk/lib/GR/BuiltinFunctionChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Added: cfe/trunk/lib/GR/Checkers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CMakeLists.txt?rev=122422&view=auto
==============================================================================
--- cfe/trunk/lib/GR/Checkers/CMakeLists.txt (added)
+++ cfe/trunk/lib/GR/Checkers/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -0,0 +1,49 @@
+add_clang_library(clangGRCheckers
+ AdjustedReturnValueChecker.cpp
+ ArrayBoundChecker.cpp
+ AttrNonNullChecker.cpp
+ BasicObjCFoundationChecks.cpp
+ BuiltinFunctionChecker.cpp
+ CallAndMessageChecker.cpp
+ CastSizeChecker.cpp
+ CastToStructChecker.cpp
+ CheckDeadStores.cpp
+ CheckObjCDealloc.cpp
+ CheckObjCInstMethSignature.cpp
+ CheckSecuritySyntaxOnly.cpp
+ CheckSizeofPointer.cpp
+ ChrootChecker.cpp
+ CStringChecker.cpp
+ DereferenceChecker.cpp
+ DivZeroChecker.cpp
+ FixedAddressChecker.cpp
+ GRExprEngineExperimentalChecks.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(clangGRCore ClangAttrClasses ClangAttrList ClangDeclNodes
+ ClangStmtNodes)
Copied: cfe/trunk/lib/GR/Checkers/CStringChecker.cpp (from r122421, cfe/trunk/lib/GR/CStringChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CStringChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/CStringChecker.cpp&p1=cfe/trunk/lib/GR/CStringChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CallAndMessageChecker.cpp (from r122421, cfe/trunk/lib/GR/CallAndMessageChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CallAndMessageChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/CallAndMessageChecker.cpp&p1=cfe/trunk/lib/GR/CallAndMessageChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CastSizeChecker.cpp (from r122421, cfe/trunk/lib/GR/CastSizeChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CastSizeChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/CastSizeChecker.cpp&p1=cfe/trunk/lib/GR/CastSizeChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CastToStructChecker.cpp (from r122421, cfe/trunk/lib/GR/CastToStructChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CastToStructChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/CastToStructChecker.cpp&p1=cfe/trunk/lib/GR/CastToStructChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CheckDeadStores.cpp (from r122421, cfe/trunk/lib/GR/CheckDeadStores.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CheckDeadStores.cpp?p2=cfe/trunk/lib/GR/Checkers/CheckDeadStores.cpp&p1=cfe/trunk/lib/GR/CheckDeadStores.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CheckObjCDealloc.cpp (from r122421, cfe/trunk/lib/GR/CheckObjCDealloc.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CheckObjCDealloc.cpp?p2=cfe/trunk/lib/GR/Checkers/CheckObjCDealloc.cpp&p1=cfe/trunk/lib/GR/CheckObjCDealloc.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CheckObjCInstMethSignature.cpp (from r122421, cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CheckObjCInstMethSignature.cpp?p2=cfe/trunk/lib/GR/Checkers/CheckObjCInstMethSignature.cpp&p1=cfe/trunk/lib/GR/CheckObjCInstMethSignature.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CheckSecuritySyntaxOnly.cpp (from r122421, cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CheckSecuritySyntaxOnly.cpp?p2=cfe/trunk/lib/GR/Checkers/CheckSecuritySyntaxOnly.cpp&p1=cfe/trunk/lib/GR/CheckSecuritySyntaxOnly.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/CheckSizeofPointer.cpp (from r122421, cfe/trunk/lib/GR/CheckSizeofPointer.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/CheckSizeofPointer.cpp?p2=cfe/trunk/lib/GR/Checkers/CheckSizeofPointer.cpp&p1=cfe/trunk/lib/GR/CheckSizeofPointer.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/ChrootChecker.cpp (from r122421, cfe/trunk/lib/GR/ChrootChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/ChrootChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/ChrootChecker.cpp&p1=cfe/trunk/lib/GR/ChrootChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/DereferenceChecker.cpp (from r122421, cfe/trunk/lib/GR/DereferenceChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/DereferenceChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/DereferenceChecker.cpp&p1=cfe/trunk/lib/GR/DereferenceChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/DivZeroChecker.cpp (from r122421, cfe/trunk/lib/GR/DivZeroChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/DivZeroChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/DivZeroChecker.cpp&p1=cfe/trunk/lib/GR/DivZeroChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/FixedAddressChecker.cpp (from r122421, cfe/trunk/lib/GR/FixedAddressChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/FixedAddressChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/FixedAddressChecker.cpp&p1=cfe/trunk/lib/GR/FixedAddressChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp (from r122421, cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp?p2=cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.cpp&p1=cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.h (from r122421, cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.h?p2=cfe/trunk/lib/GR/Checkers/GRExprEngineExperimentalChecks.h&p1=cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/GRExprEngineInternalChecks.h (from r122421, cfe/trunk/lib/GR/GRExprEngineInternalChecks.h)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/GRExprEngineInternalChecks.h?p2=cfe/trunk/lib/GR/Checkers/GRExprEngineInternalChecks.h&p1=cfe/trunk/lib/GR/GRExprEngineInternalChecks.h&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/IdempotentOperationChecker.cpp (from r122421, cfe/trunk/lib/GR/IdempotentOperationChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/IdempotentOperationChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/IdempotentOperationChecker.cpp&p1=cfe/trunk/lib/GR/IdempotentOperationChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/LLVMConventionsChecker.cpp (from r122421, cfe/trunk/lib/GR/LLVMConventionsChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/LLVMConventionsChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/LLVMConventionsChecker.cpp&p1=cfe/trunk/lib/GR/LLVMConventionsChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/MacOSXAPIChecker.cpp (from r122421, cfe/trunk/lib/GR/MacOSXAPIChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/MacOSXAPIChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/MacOSXAPIChecker.cpp&p1=cfe/trunk/lib/GR/MacOSXAPIChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/Makefile (from r122421, cfe/trunk/lib/GR/Makefile)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/Makefile?p2=cfe/trunk/lib/GR/Checkers/Makefile&p1=cfe/trunk/lib/GR/Makefile&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
--- cfe/trunk/lib/GR/Makefile (original)
+++ cfe/trunk/lib/GR/Checkers/Makefile Wed Dec 22 12:52:56 2010
@@ -11,8 +11,7 @@
#
##===----------------------------------------------------------------------===##
-CLANG_LEVEL := ../..
-LIBRARYNAME := clangGRCore
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangGRCheckers
include $(CLANG_LEVEL)/Makefile
-
Copied: cfe/trunk/lib/GR/Checkers/MallocChecker.cpp (from r122421, cfe/trunk/lib/GR/MallocChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/MallocChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/MallocChecker.cpp&p1=cfe/trunk/lib/GR/MallocChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp (from r122421, cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/NSAutoreleasePoolChecker.cpp&p1=cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/NSErrorChecker.cpp (from r122421, cfe/trunk/lib/GR/NSErrorChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/NSErrorChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/NSErrorChecker.cpp&p1=cfe/trunk/lib/GR/NSErrorChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/NoReturnFunctionChecker.cpp (from r122421, cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/NoReturnFunctionChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/NoReturnFunctionChecker.cpp&p1=cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/OSAtomicChecker.cpp (from r122421, cfe/trunk/lib/GR/OSAtomicChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/OSAtomicChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/OSAtomicChecker.cpp&p1=cfe/trunk/lib/GR/OSAtomicChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/ObjCAtSyncChecker.cpp (from r122421, cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/ObjCAtSyncChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/ObjCAtSyncChecker.cpp&p1=cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/ObjCUnusedIVarsChecker.cpp (from r122421, cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/ObjCUnusedIVarsChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/ObjCUnusedIVarsChecker.cpp&p1=cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/PointerArithChecker.cpp (from r122421, cfe/trunk/lib/GR/PointerArithChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/PointerArithChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/PointerArithChecker.cpp&p1=cfe/trunk/lib/GR/PointerArithChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/PointerSubChecker.cpp (from r122421, cfe/trunk/lib/GR/PointerSubChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/PointerSubChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/PointerSubChecker.cpp&p1=cfe/trunk/lib/GR/PointerSubChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/PthreadLockChecker.cpp (from r122421, cfe/trunk/lib/GR/PthreadLockChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/PthreadLockChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/PthreadLockChecker.cpp&p1=cfe/trunk/lib/GR/PthreadLockChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/ReturnPointerRangeChecker.cpp (from r122421, cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/ReturnPointerRangeChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/ReturnPointerRangeChecker.cpp&p1=cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/ReturnUndefChecker.cpp (from r122421, cfe/trunk/lib/GR/ReturnUndefChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/ReturnUndefChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/ReturnUndefChecker.cpp&p1=cfe/trunk/lib/GR/ReturnUndefChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/StackAddrLeakChecker.cpp (from r122421, cfe/trunk/lib/GR/StackAddrLeakChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/StackAddrLeakChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/StackAddrLeakChecker.cpp&p1=cfe/trunk/lib/GR/StackAddrLeakChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/StreamChecker.cpp (from r122421, cfe/trunk/lib/GR/StreamChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/StreamChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/StreamChecker.cpp&p1=cfe/trunk/lib/GR/StreamChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UndefBranchChecker.cpp (from r122421, cfe/trunk/lib/GR/UndefBranchChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UndefBranchChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UndefBranchChecker.cpp&p1=cfe/trunk/lib/GR/UndefBranchChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp (from r122421, cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UndefCapturedBlockVarChecker.cpp&p1=cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UndefResultChecker.cpp (from r122421, cfe/trunk/lib/GR/UndefResultChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UndefResultChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UndefResultChecker.cpp&p1=cfe/trunk/lib/GR/UndefResultChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp (from r122421, cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UndefinedArraySubscriptChecker.cpp&p1=cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UndefinedAssignmentChecker.cpp (from r122421, cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UndefinedAssignmentChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UndefinedAssignmentChecker.cpp&p1=cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UnixAPIChecker.cpp (from r122421, cfe/trunk/lib/GR/UnixAPIChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UnixAPIChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UnixAPIChecker.cpp&p1=cfe/trunk/lib/GR/UnixAPIChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/UnreachableCodeChecker.cpp (from r122421, cfe/trunk/lib/GR/UnreachableCodeChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/UnreachableCodeChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/UnreachableCodeChecker.cpp&p1=cfe/trunk/lib/GR/UnreachableCodeChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Copied: cfe/trunk/lib/GR/Checkers/VLASizeChecker.cpp (from r122421, cfe/trunk/lib/GR/VLASizeChecker.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Checkers/VLASizeChecker.cpp?p2=cfe/trunk/lib/GR/Checkers/VLASizeChecker.cpp&p1=cfe/trunk/lib/GR/VLASizeChecker.cpp&r1=122421&r2=122422&rev=122422&view=diff
==============================================================================
(empty)
Removed: cfe/trunk/lib/GR/ChrootChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/ChrootChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/ChrootChecker.cpp (original)
+++ cfe/trunk/lib/GR/ChrootChecker.cpp (removed)
@@ -1,161 +0,0 @@
-//===- 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 "GRExprEngineExperimentalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRState.h"
-#include "clang/GR/PathSensitive/GRStateTrait.h"
-#include "clang/GR/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/ImmutableMap.h"
-using namespace clang;
-
-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 clang::RegisterChrootChecker(GRExprEngine &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;
-}
Removed: cfe/trunk/lib/GR/DereferenceChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/DereferenceChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/DereferenceChecker.cpp (original)
+++ cfe/trunk/lib/GR/DereferenceChecker.cpp (removed)
@@ -1,203 +0,0 @@
-//== 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 GRExprEngine that performs
-// checks for null pointers at loads and stores.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/Checkers/DereferenceChecker.h"
-#include "clang/GR/PathSensitive/Checker.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-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 clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new DereferenceChecker());
-}
-
-std::pair<ExplodedNode * const *, ExplodedNode * const *>
-clang::GetImplicitNullDereferences(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/DivZeroChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/DivZeroChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/DivZeroChecker.cpp (original)
+++ cfe/trunk/lib/GR/DivZeroChecker.cpp (removed)
@@ -1,85 +0,0 @@
-//== 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 GRExprEngine that performs
-// checks for division by zeros.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterDivZeroChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/FixedAddressChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/FixedAddressChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/FixedAddressChecker.cpp (original)
+++ cfe/trunk/lib/GR/FixedAddressChecker.cpp (removed)
@@ -1,71 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterFixedAddressChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new FixedAddressChecker());
-}
Modified: cfe/trunk/lib/GR/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/GRExprEngine.cpp?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/lib/GR/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/GR/GRExprEngine.cpp Wed Dec 22 12:52:56 2010
@@ -12,7 +12,10 @@
// functions and build the ExplodedGraph at the expression level.
//
//===----------------------------------------------------------------------===//
-#include "GRExprEngineInternalChecks.h"
+
+// FIXME: Restructure checker registration.
+#include "Checkers/GRExprEngineInternalChecks.h"
+
#include "clang/GR/BugReporter/BugType.h"
#include "clang/GR/PathSensitive/AnalysisManager.h"
#include "clang/GR/PathSensitive/GRExprEngine.h"
Removed: cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp (original)
+++ cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.cpp (removed)
@@ -1,45 +0,0 @@
-//=-- GRExprEngineExperimentalChecks.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 GRExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "GRExprEngineExperimentalChecks.h"
-#include "clang/GR/Checkers/LocalCheckers.h"
-
-using namespace clang;
-
-void clang::RegisterExperimentalChecks(GRExprEngine &Eng) {
- // These are checks that never belong as internal checks
- // within GRExprEngine.
- RegisterCStringChecker(Eng);
- RegisterChrootChecker(Eng);
- RegisterMallocChecker(Eng);
- RegisterPthreadLockChecker(Eng);
- RegisterStreamChecker(Eng);
- RegisterUnreachableCodeChecker(Eng);
-}
-
-void clang::RegisterExperimentalInternalChecks(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h (original)
+++ cfe/trunk/lib/GR/GRExprEngineExperimentalChecks.h (removed)
@@ -1,32 +0,0 @@
-//=-- GRExprEngineExperimentalChecks.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 GRExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
-#define LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
-
-namespace clang {
-
-class GRExprEngine;
-
-void RegisterAnalyzerStatsChecker(GRExprEngine &Eng);
-void RegisterChrootChecker(GRExprEngine &Eng);
-void RegisterCStringChecker(GRExprEngine &Eng);
-void RegisterIdempotentOperationChecker(GRExprEngine &Eng);
-void RegisterMallocChecker(GRExprEngine &Eng);
-void RegisterPthreadLockChecker(GRExprEngine &Eng);
-void RegisterStreamChecker(GRExprEngine &Eng);
-void RegisterUnreachableCodeChecker(GRExprEngine &Eng);
-
-} // end clang namespace
-#endif
Removed: cfe/trunk/lib/GR/GRExprEngineInternalChecks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/GRExprEngineInternalChecks.h?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/GRExprEngineInternalChecks.h (original)
+++ cfe/trunk/lib/GR/GRExprEngineInternalChecks.h (removed)
@@ -1,53 +0,0 @@
-//=-- GRExprEngineInternalChecks.h- Builtin GRExprEngine 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 GRExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS
-#define LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS
-
-namespace clang {
-
-class GRExprEngine;
-
-// Foundational checks that handle basic semantics.
-void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng);
-void RegisterArrayBoundChecker(GRExprEngine &Eng);
-void RegisterAttrNonNullChecker(GRExprEngine &Eng);
-void RegisterBuiltinFunctionChecker(GRExprEngine &Eng);
-void RegisterCallAndMessageChecker(GRExprEngine &Eng);
-void RegisterCastToStructChecker(GRExprEngine &Eng);
-void RegisterCastSizeChecker(GRExprEngine &Eng);
-void RegisterDereferenceChecker(GRExprEngine &Eng);
-void RegisterDivZeroChecker(GRExprEngine &Eng);
-void RegisterFixedAddressChecker(GRExprEngine &Eng);
-void RegisterNoReturnFunctionChecker(GRExprEngine &Eng);
-void RegisterObjCAtSyncChecker(GRExprEngine &Eng);
-void RegisterPointerArithChecker(GRExprEngine &Eng);
-void RegisterPointerSubChecker(GRExprEngine &Eng);
-void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
-void RegisterReturnUndefChecker(GRExprEngine &Eng);
-void RegisterStackAddrLeakChecker(GRExprEngine &Eng);
-void RegisterUndefBranchChecker(GRExprEngine &Eng);
-void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng);
-void RegisterUndefResultChecker(GRExprEngine &Eng);
-void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
-void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
-void RegisterVLASizeChecker(GRExprEngine &Eng);
-
-// API checks.
-void RegisterMacOSXAPIChecker(GRExprEngine &Eng);
-void RegisterOSAtomicChecker(GRExprEngine &Eng);
-void RegisterUnixAPIChecker(GRExprEngine &Eng);
-
-} // end clang namespace
-#endif
Removed: cfe/trunk/lib/GR/IdempotentOperationChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/IdempotentOperationChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/IdempotentOperationChecker.cpp (original)
+++ cfe/trunk/lib/GR/IdempotentOperationChecker.cpp (removed)
@@ -1,833 +0,0 @@
-//==- 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 "GRExprEngineExperimentalChecks.h"
-#include "clang/Analysis/CFGStmtMap.h"
-#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
-#include "clang/GR/BugReporter/BugReporter.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerHelpers.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRCoreEngine.h"
-#include "clang/GR/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;
-
-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, GRExprEngine &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 GRCoreEngine &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 clang::RegisterIdempotentOperationChecker(GRExprEngine &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,
- GRExprEngine &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 GRCoreEngine &CE) {
- // Test for reachability from any aborted blocks to this block
- typedef GRCoreEngine::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 GRWorkList::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 GRWorkListUnit &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);
- }
-}
Removed: cfe/trunk/lib/GR/LLVMConventionsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/LLVMConventionsChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/LLVMConventionsChecker.cpp (original)
+++ cfe/trunk/lib/GR/LLVMConventionsChecker.cpp (removed)
@@ -1,312 +0,0 @@
-//=== 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/GR/Checkers/LocalCheckers.h"
-#include "clang/GR/BugReporter/BugReporter.h"
-#include <string>
-#include "llvm/ADT/StringRef.h"
-
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// 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 clang::CheckLLVMConventions(TranslationUnitDecl &TU,
- BugReporter &BR) {
- ScanCodeDecls(&TU, BR);
-}
-
Removed: cfe/trunk/lib/GR/MacOSXAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/MacOSXAPIChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/MacOSXAPIChecker.cpp (original)
+++ cfe/trunk/lib/GR/MacOSXAPIChecker.cpp (removed)
@@ -1,141 +0,0 @@
-// 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 "GRExprEngineInternalChecks.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRStateTrait.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-
-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 clang::RegisterMacOSXAPIChecker(GRExprEngine &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);
-}
Modified: cfe/trunk/lib/GR/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/Makefile?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/lib/GR/Makefile (original)
+++ cfe/trunk/lib/GR/Makefile Wed Dec 22 12:52:56 2010
@@ -13,6 +13,7 @@
CLANG_LEVEL := ../..
LIBRARYNAME := clangGRCore
+PARALLEL_DIRS := Checkers
include $(CLANG_LEVEL)/Makefile
Removed: cfe/trunk/lib/GR/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/MallocChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/MallocChecker.cpp (original)
+++ cfe/trunk/lib/GR/MallocChecker.cpp (removed)
@@ -1,730 +0,0 @@
-//=== 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 "GRExprEngineExperimentalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRState.h"
-#include "clang/GR/PathSensitive/GRStateTrait.h"
-#include "clang/GR/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/ImmutableMap.h"
-using namespace clang;
-
-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(GREndPathNodeBuilder &B, void *tag, GRExprEngine &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 {
- template <>
- struct GRStateTrait<RegionState>
- : public GRStatePartialTrait<RegionStateTy> {
- static void *GDMIndex() { return MallocChecker::getTag(); }
- };
-}
-
-void clang::RegisterMallocChecker(GRExprEngine &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(GREndPathNodeBuilder &B, void *tag,
- GRExprEngine &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);
- }
- }
-}
Removed: cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp (original)
+++ cfe/trunk/lib/GR/NSAutoreleasePoolChecker.cpp (removed)
@@ -1,86 +0,0 @@
-//=- 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/GR/BugReporter/BugReporter.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "BasicObjCFoundationChecks.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
-
-using namespace clang;
-
-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 clang::RegisterNSAutoreleasePoolChecks(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/NSErrorChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/NSErrorChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/NSErrorChecker.cpp (original)
+++ cfe/trunk/lib/GR/NSErrorChecker.cpp (removed)
@@ -1,237 +0,0 @@
-//=- 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/GR/Checkers/LocalCheckers.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-#include "clang/GR/Checkers/DereferenceChecker.h"
-#include "BasicObjCFoundationChecks.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallVector.h"
-
-using namespace clang;
-
-namespace {
-class NSErrorChecker : public BugType {
- const Decl &CodeDecl;
- const bool isNSErrorWarning;
- IdentifierInfo * const II;
- GRExprEngine &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, GRExprEngine& 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 clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &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);
- }
-}
Removed: cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp (original)
+++ cfe/trunk/lib/GR/NoReturnFunctionChecker.cpp (removed)
@@ -1,79 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "llvm/ADT/StringSwitch.h"
-
-using namespace clang;
-
-namespace {
-
-class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> {
-public:
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-
-}
-
-void clang::RegisterNoReturnFunctionChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/OSAtomicChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/OSAtomicChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/OSAtomicChecker.cpp (original)
+++ cfe/trunk/lib/GR/OSAtomicChecker.cpp (removed)
@@ -1,202 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/PathSensitive/Checker.h"
-#include "clang/Basic/Builtins.h"
-
-using namespace clang;
-
-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 clang::RegisterOSAtomicChecker(GRExprEngine &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'.
- GRExprEngine &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;
-}
Removed: cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp (original)
+++ cfe/trunk/lib/GR/ObjCAtSyncChecker.cpp (removed)
@@ -1,94 +0,0 @@
-//== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/Checkers/DereferenceChecker.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-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 clang::RegisterObjCAtSyncChecker(GRExprEngine &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);
-}
-
Removed: cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp (original)
+++ cfe/trunk/lib/GR/ObjCUnusedIVarsChecker.cpp (removed)
@@ -1,163 +0,0 @@
-//==- 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/GR/Checkers/LocalCheckers.h"
-#include "clang/GR/BugReporter/PathDiagnostic.h"
-#include "clang/GR/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;
-
-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 clang::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());
- }
-}
Removed: cfe/trunk/lib/GR/PointerArithChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/PointerArithChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/PointerArithChecker.cpp (original)
+++ cfe/trunk/lib/GR/PointerArithChecker.cpp (removed)
@@ -1,71 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterPointerArithChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new PointerArithChecker());
-}
Removed: cfe/trunk/lib/GR/PointerSubChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/PointerSubChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/PointerSubChecker.cpp (original)
+++ cfe/trunk/lib/GR/PointerSubChecker.cpp (removed)
@@ -1,78 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterPointerSubChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new PointerSubChecker());
-}
Removed: cfe/trunk/lib/GR/PthreadLockChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/PthreadLockChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/PthreadLockChecker.cpp (original)
+++ cfe/trunk/lib/GR/PthreadLockChecker.cpp (removed)
@@ -1,144 +0,0 @@
-//===--- 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 GRExprEngineInternalChecks.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/BugReporter/BugReporter.h"
-#include "clang/GR/PathSensitive/GRStateTrait.h"
-#include "GRExprEngineExperimentalChecks.h"
-#include "llvm/ADT/ImmutableSet.h"
-
-using namespace clang;
-
-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 {
-template <> struct GRStateTrait<LockSet> :
- public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { return PthreadLockChecker::getTag(); }
-};
-} // end clang namespace
-
-void clang::RegisterPthreadLockChecker(GRExprEngine &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));
-}
Removed: cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp (original)
+++ cfe/trunk/lib/GR/ReturnPointerRangeChecker.cpp (removed)
@@ -1,94 +0,0 @@
-//== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-namespace {
-class ReturnPointerRangeChecker :
- public CheckerVisitor<ReturnPointerRangeChecker> {
- BuiltinBug *BT;
-public:
- ReturnPointerRangeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
-};
-}
-
-void clang::RegisterReturnPointerRangeChecker(GRExprEngine &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);
- }
-}
Removed: cfe/trunk/lib/GR/ReturnUndefChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/ReturnUndefChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/ReturnUndefChecker.cpp (original)
+++ cfe/trunk/lib/GR/ReturnUndefChecker.cpp (removed)
@@ -1,68 +0,0 @@
-//== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-namespace {
-class ReturnUndefChecker :
- public CheckerVisitor<ReturnUndefChecker> {
- BuiltinBug *BT;
-public:
- ReturnUndefChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
-};
-}
-
-void clang::RegisterReturnUndefChecker(GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/StackAddrLeakChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/StackAddrLeakChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/StackAddrLeakChecker.cpp (original)
+++ cfe/trunk/lib/GR/StackAddrLeakChecker.cpp (removed)
@@ -1,204 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRState.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
-using namespace clang;
-
-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(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
-private:
- void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
- SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
- SourceManager &SM);
-};
-}
-
-void clang::RegisterStackAddrLeakChecker(GRExprEngine &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(GREndPathNodeBuilder &B, void *tag,
- GRExprEngine &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);
- }
-}
Removed: cfe/trunk/lib/GR/StreamChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/StreamChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/StreamChecker.cpp (original)
+++ cfe/trunk/lib/GR/StreamChecker.cpp (removed)
@@ -1,463 +0,0 @@
-//===-- 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 "GRExprEngineExperimentalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRState.h"
-#include "clang/GR/PathSensitive/GRStateTrait.h"
-#include "clang/GR/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/ImmutableMap.h"
-
-using namespace clang;
-
-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(GREndPathNodeBuilder &B, void *tag, GRExprEngine &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 {
- template <>
- struct GRStateTrait<StreamState>
- : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
- static void *GDMIndex() { return StreamChecker::getTag(); }
- };
-}
-
-void clang::RegisterStreamChecker(GRExprEngine &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(GREndPathNodeBuilder &B, void *tag,
- GRExprEngine &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);
-}
Removed: cfe/trunk/lib/GR/UndefBranchChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UndefBranchChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UndefBranchChecker.cpp (original)
+++ cfe/trunk/lib/GR/UndefBranchChecker.cpp (removed)
@@ -1,119 +0,0 @@
-//=== 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/Checker.h"
-
-using namespace clang;
-
-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(GRBranchNodeBuilder &Builder, GRExprEngine &Eng,
- const Stmt *Condition, void *tag);
-};
-
-}
-
-void clang::RegisterUndefBranchChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new UndefBranchChecker());
-}
-
-void *UndefBranchChecker::getTag() {
- static int x;
- return &x;
-}
-
-void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder,
- GRExprEngine &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);
- }
-}
Removed: cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp (original)
+++ cfe/trunk/lib/GR/UndefCapturedBlockVarChecker.cpp (removed)
@@ -1,101 +0,0 @@
-// 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 "GRExprEngineInternalChecks.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-
-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 clang::RegisterUndefCapturedBlockVarChecker(GRExprEngine &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);
- }
- }
-}
Removed: cfe/trunk/lib/GR/UndefResultChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UndefResultChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UndefResultChecker.cpp (original)
+++ cfe/trunk/lib/GR/UndefResultChecker.cpp (removed)
@@ -1,86 +0,0 @@
-//=== 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 GRExprEngine that
-// performs checks for undefined results of non-assignment binary operators.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-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 clang::RegisterUndefResultChecker(GRExprEngine &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);
- }
-}
Removed: cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp (original)
+++ cfe/trunk/lib/GR/UndefinedArraySubscriptChecker.cpp (removed)
@@ -1,56 +0,0 @@
-//===--- 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 GRExprEngine
-// that performs checks for undefined array subscripts.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterUndefinedArraySubscriptChecker(GRExprEngine &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);
- }
- }
-}
Removed: cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp (original)
+++ cfe/trunk/lib/GR/UndefinedAssignmentChecker.cpp (removed)
@@ -1,93 +0,0 @@
-//===--- 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 GRExprEngine that
-// checks for assigning undefined values.
-//
-//===----------------------------------------------------------------------===//
-
-#include "GRExprEngineInternalChecks.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-
-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 clang::RegisterUndefinedAssignmentChecker(GRExprEngine &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);
-}
-
Removed: cfe/trunk/lib/GR/UnixAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UnixAPIChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UnixAPIChecker.cpp (original)
+++ cfe/trunk/lib/GR/UnixAPIChecker.cpp (removed)
@@ -1,276 +0,0 @@
-//= 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 "GRExprEngineInternalChecks.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringSwitch.h"
-#include <fcntl.h>
-
-using namespace clang;
-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 clang::RegisterUnixAPIChecker(GRExprEngine &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 GRExprEngine.
- 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);
-}
Removed: cfe/trunk/lib/GR/UnreachableCodeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/UnreachableCodeChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/UnreachableCodeChecker.cpp (original)
+++ cfe/trunk/lib/GR/UnreachableCodeChecker.cpp (removed)
@@ -1,222 +0,0 @@
-//==- 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/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/ExplodedGraph.h"
-#include "clang/GR/PathSensitive/SVals.h"
-#include "clang/GR/PathSensitive/CheckerHelpers.h"
-#include "clang/GR/BugReporter/BugReporter.h"
-#include "GRExprEngineExperimentalChecks.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;
-
-namespace {
-class UnreachableCodeChecker : public Checker {
-public:
- static void *getTag();
- void VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- GRExprEngine &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 clang::RegisterUnreachableCodeChecker(GRExprEngine &Eng) {
- Eng.registerCheck(new UnreachableCodeChecker());
-}
-
-void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- GRExprEngine &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
-}
Removed: cfe/trunk/lib/GR/VLASizeChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/GR/VLASizeChecker.cpp?rev=122421&view=auto
==============================================================================
--- cfe/trunk/lib/GR/VLASizeChecker.cpp (original)
+++ cfe/trunk/lib/GR/VLASizeChecker.cpp (removed)
@@ -1,137 +0,0 @@
-//=== 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 GRExprEngine 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 "GRExprEngineInternalChecks.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/GR/BugReporter/BugType.h"
-#include "clang/GR/PathSensitive/CheckerVisitor.h"
-#include "clang/GR/PathSensitive/GRExprEngine.h"
-
-using namespace clang;
-
-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 clang::RegisterVLASizeChecker(GRExprEngine &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);
-}
Modified: cfe/trunk/tools/driver/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/CMakeLists.txt?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/tools/driver/CMakeLists.txt (original)
+++ cfe/trunk/tools/driver/CMakeLists.txt Wed Dec 22 12:52:56 2010
@@ -8,6 +8,7 @@
clangCodeGen
clangParse
clangSema
+ clangGRCheckers
clangGRCore
clangAnalysis
clangIndex
Modified: cfe/trunk/tools/driver/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/Makefile?rev=122422&r1=122421&r2=122422&view=diff
==============================================================================
--- cfe/trunk/tools/driver/Makefile (original)
+++ cfe/trunk/tools/driver/Makefile Wed Dec 22 12:52:56 2010
@@ -39,7 +39,7 @@
ipo selectiondag
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
- clangGRCore.a clangAnalysis.a clangIndex.a clangRewrite.a \
+ clangGRCheckers.a clangGRCore.a clangAnalysis.a clangIndex.a clangRewrite.a \
clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
More information about the cfe-commits
mailing list