clang API Documentation

BoolAssignmentChecker.cpp
Go to the documentation of this file.
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 }