clang API Documentation
00001 //== BoolAssignmentChecker.cpp - Boolean assignment checker -----*- C++ -*--==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines BoolAssignmentChecker, a builtin check in ExprEngine that 00011 // performs checks for assignment of non-Boolean values to Boolean variables. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00017 #include "clang/StaticAnalyzer/Core/Checker.h" 00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00020 00021 using namespace clang; 00022 using namespace ento; 00023 00024 namespace { 00025 class BoolAssignmentChecker : public Checker< check::Bind > { 00026 mutable std::unique_ptr<BuiltinBug> BT; 00027 void emitReport(ProgramStateRef state, CheckerContext &C) const; 00028 public: 00029 void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const; 00030 }; 00031 } // end anonymous namespace 00032 00033 void BoolAssignmentChecker::emitReport(ProgramStateRef state, 00034 CheckerContext &C) const { 00035 if (ExplodedNode *N = C.addTransition(state)) { 00036 if (!BT) 00037 BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value")); 00038 C.emitReport(new BugReport(*BT, BT->getDescription(), N)); 00039 } 00040 } 00041 00042 static bool isBooleanType(QualType Ty) { 00043 if (Ty->isBooleanType()) // C++ or C99 00044 return true; 00045 00046 if (const TypedefType *TT = Ty->getAs<TypedefType>()) 00047 return TT->getDecl()->getName() == "BOOL" || // Objective-C 00048 TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99 00049 TT->getDecl()->getName() == "Boolean"; // MacTypes.h 00050 00051 return false; 00052 } 00053 00054 void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S, 00055 CheckerContext &C) const { 00056 00057 // We are only interested in stores into Booleans. 00058 const TypedValueRegion *TR = 00059 dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion()); 00060 00061 if (!TR) 00062 return; 00063 00064 QualType valTy = TR->getValueType(); 00065 00066 if (!isBooleanType(valTy)) 00067 return; 00068 00069 // Get the value of the right-hand side. We only care about values 00070 // that are defined (UnknownVals and UndefinedVals are handled by other 00071 // checkers). 00072 Optional<DefinedSVal> DV = val.getAs<DefinedSVal>(); 00073 if (!DV) 00074 return; 00075 00076 // Check if the assigned value meets our criteria for correctness. It must 00077 // be a value that is either 0 or 1. One way to check this is to see if 00078 // the value is possibly < 0 (for a negative value) or greater than 1. 00079 ProgramStateRef state = C.getState(); 00080 SValBuilder &svalBuilder = C.getSValBuilder(); 00081 ConstraintManager &CM = C.getConstraintManager(); 00082 00083 // First, ensure that the value is >= 0. 00084 DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy); 00085 SVal greaterThanOrEqualToZeroVal = 00086 svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal, 00087 svalBuilder.getConditionType()); 00088 00089 Optional<DefinedSVal> greaterThanEqualToZero = 00090 greaterThanOrEqualToZeroVal.getAs<DefinedSVal>(); 00091 00092 if (!greaterThanEqualToZero) { 00093 // The SValBuilder cannot construct a valid SVal for this condition. 00094 // This means we cannot properly reason about it. 00095 return; 00096 } 00097 00098 ProgramStateRef stateLT, stateGE; 00099 std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero); 00100 00101 // Is it possible for the value to be less than zero? 00102 if (stateLT) { 00103 // It is possible for the value to be less than zero. We only 00104 // want to emit a warning, however, if that value is fully constrained. 00105 // If it it possible for the value to be >= 0, then essentially the 00106 // value is underconstrained and there is nothing left to be done. 00107 if (!stateGE) 00108 emitReport(stateLT, C); 00109 00110 // In either case, we are done. 00111 return; 00112 } 00113 00114 // If we reach here, it must be the case that the value is constrained 00115 // to only be >= 0. 00116 assert(stateGE == state); 00117 00118 // At this point we know that the value is >= 0. 00119 // Now check to ensure that the value is <= 1. 00120 DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy); 00121 SVal lessThanEqToOneVal = 00122 svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal, 00123 svalBuilder.getConditionType()); 00124 00125 Optional<DefinedSVal> lessThanEqToOne = 00126 lessThanEqToOneVal.getAs<DefinedSVal>(); 00127 00128 if (!lessThanEqToOne) { 00129 // The SValBuilder cannot construct a valid SVal for this condition. 00130 // This means we cannot properly reason about it. 00131 return; 00132 } 00133 00134 ProgramStateRef stateGT, stateLE; 00135 std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne); 00136 00137 // Is it possible for the value to be greater than one? 00138 if (stateGT) { 00139 // It is possible for the value to be greater than one. We only 00140 // want to emit a warning, however, if that value is fully constrained. 00141 // If it is possible for the value to be <= 1, then essentially the 00142 // value is underconstrained and there is nothing left to be done. 00143 if (!stateLE) 00144 emitReport(stateGT, C); 00145 00146 // In either case, we are done. 00147 return; 00148 } 00149 00150 // If we reach here, it must be the case that the value is constrained 00151 // to only be <= 1. 00152 assert(stateLE == state); 00153 } 00154 00155 void ento::registerBoolAssignmentChecker(CheckerManager &mgr) { 00156 mgr.registerChecker<BoolAssignmentChecker>(); 00157 }