]> granicus.if.org Git - clang/commitdiff
Add corner case logic to BasicStoreManager and GRSimpleVals::EvalBinOp to enable
authorTed Kremenek <kremenek@apple.com>
Wed, 29 Apr 2009 16:03:27 +0000 (16:03 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 29 Apr 2009 16:03:27 +0000 (16:03 +0000)
reasoning about OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier. Essentially
the address of reference to a region (pointer-to-pointer) can be casted to
(int32_t*), and we need to handle the logic to convert the involved locations
back and forth from nonloc::LocAsInteger, nonloc::ConcreteInt, to Loc and
loc::ConcreteInt respectively. This adds some potentially suspect logic to
BasicStoreManager that allows the analyzer to reason about abuses of the C type
system. This should probably be refined, be ported over to RegionStoreManager,
and extended with "path-sensitive type checking" to flag bugs in clearly
incoherent code.

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

lib/Analysis/BasicStore.cpp
lib/Analysis/GRSimpleVals.cpp

index 616c4b51350ab9ce7e8dcacc09b68fa7610ed5cb..c9bf9ea566275a024fef342dfcf3254f86355dfc 100644 (file)
@@ -251,7 +251,7 @@ SVal BasicStoreManager::getLValueElement(const GRState* St, SVal Base,
     return UnknownVal();
 }
 
-static bool isHigherOrderVoidPtr(QualType T, ASTContext &C) {
+static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
   bool foundPointer = false;
   while (1) {  
     const PointerType *PT = T->getAsPointerType();
@@ -259,6 +259,10 @@ static bool isHigherOrderVoidPtr(QualType T, ASTContext &C) {
       if (!foundPointer)
         return false;
       
+      // intptr_t* or intptr_t**, etc?
+      if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy))
+        return true;
+      
       QualType X = C.getCanonicalType(T).getUnqualifiedType();
       return X == C.VoidTy;
     }
@@ -267,7 +271,7 @@ static bool isHigherOrderVoidPtr(QualType T, ASTContext &C) {
     T = PT->getPointeeType();
   }  
 }
-
 SVal BasicStoreManager::Retrieve(const GRState* state, Loc loc, QualType T) {
   
   if (isa<UnknownVal>(loc))
@@ -281,12 +285,12 @@ SVal BasicStoreManager::Retrieve(const GRState* state, Loc loc, QualType T) {
       const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
       
       if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
-        // Just support void**, void***, etc., for now.  This is needed
-        // to handle OSCompareAndSwapPtr().
+        // Just support void**, void***, intptr_t*, intptr_t**, etc., for now.
+        // This is needed to handle OSCompareAndSwapPtr() and friends.
         ASTContext &Ctx = StateMgr.getContext();
         QualType T = TR->getLValueType(Ctx);
 
-        if (!isHigherOrderVoidPtr(T, Ctx))
+        if (!isHigherOrderRawPtr(T, Ctx))
           return UnknownVal();
         
         // Otherwise, strip the views.
@@ -321,6 +325,33 @@ Store BasicStoreManager::BindInternal(Store store, Loc loc, SVal V) {
     case loc::MemRegionKind: {
       const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
       
+      // Special case: handle store of pointer values (Loc) to pointers via
+      // a cast to intXX_t*, void*, etc.  This is needed to handle
+      // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier.
+      if (isa<Loc>(V) || isa<nonloc::LocAsInteger>(V))
+        if (const TypedViewRegion *TR = dyn_cast<TypedViewRegion>(R)) {
+          ASTContext &C = StateMgr.getContext();
+          QualType T = TR->getLValueType(C);
+        
+          if (isHigherOrderRawPtr(T, C)) {
+            R = TR->removeViews();
+            
+            if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&V)) {
+              // Only convert 'V' to a location iff the underlying region type
+              // is a location as well.
+              // FIXME: We are allowing a store of an arbitrary location to
+              // a pointer.  We may wish to flag a type error here if the types
+              // are incompatible.  This may also cause lots of breakage
+              // elsewhere. Food for thought.
+              if (const TypedRegion *TyR = dyn_cast<TypedRegion>(R)) {
+                if (TyR->isBoundable(C) &&
+                    Loc::IsLocType(TyR->getRValueType(C)))              
+                  V = X->getLoc();
+              }
+            }
+          }
+        }      
+      
       if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
         return store;
       
index 413ef7b5ba702aebb1e79e9f9301bace07894790..860013872e490e04f69134578bce6f9c1b128e15 100644 (file)
@@ -262,7 +262,22 @@ SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
 }
 
 SVal GRSimpleVals::EvalBinOp(GRExprEngine& Eng, BinaryOperator::Opcode Op,
-                             Loc L, NonLoc R) {  
+                             Loc L, NonLoc R) {
+  
+  // Special case: 'R' is an integer that has the same width as a pointer and
+  // we are using the integer location in a comparison.  Normally this cannot be
+  // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+  // can generate comparisons that trigger this code.
+  // FIXME: Are all locations guaranteed to have pointer width?
+  if (BinaryOperator::isEqualityOp(Op)) {
+    if (nonloc::ConcreteInt *RInt = dyn_cast<nonloc::ConcreteInt>(&R)) {
+      const llvm::APSInt &X = RInt->getValue();
+      ASTContext &C = Eng.getContext();
+      if (C.getTypeSize(C.VoidPtrTy) == X.getBitWidth())
+        return EvalBinOp(Eng, Op, L, loc::ConcreteInt(X));
+    }
+  }
+  
   // Delegate pointer arithmetic to store manager.
   return Eng.getStoreManager().EvalBinOp(Op, L, R);
 }