diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/BasicValueFactory.h | 5 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/MemRegion.h | 8 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/SVals.h | 4 | ||||
-rw-r--r-- | lib/Analysis/MemRegion.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 29 | ||||
-rw-r--r-- | lib/Analysis/SVals.cpp | 7 | ||||
-rw-r--r-- | test/Analysis/rdar-6541136-region.c | 19 | ||||
-rw-r--r-- | test/Analysis/rdar-6541136.c | 20 |
8 files changed, 78 insertions, 19 deletions
diff --git a/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/include/clang/Analysis/PathSensitive/BasicValueFactory.h index bf6bb8c807..1e08fb9a02 100644 --- a/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ b/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -76,6 +76,11 @@ public: const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); const llvm::APSInt& getValue(uint64_t X, QualType T); + const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; + return getValue(X, T); + } + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } diff --git a/include/clang/Analysis/PathSensitive/MemRegion.h b/include/clang/Analysis/PathSensitive/MemRegion.h index 80efac4dbf..8a62eff7a9 100644 --- a/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/include/clang/Analysis/PathSensitive/MemRegion.h @@ -173,6 +173,14 @@ public: // FIXME: We can possibly optimize this later to cache this value. return C.getPointerType(getRValueType(C)); } + + QualType getDesugaredRValueType(ASTContext& C) const { + return getRValueType(C)->getDesugaredType(); + } + + QualType getDesugaredLValueType(ASTContext& C) const { + return getLValueType(C)->getDesugaredType(); + } static bool classof(const MemRegion* R) { unsigned k = R->getKind(); diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h index dbeba45c83..a0bc3ed186 100644 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -171,8 +171,8 @@ public: static NonLoc MakeVal(SymbolRef sym); - static NonLoc MakeVal(BasicValueFactory& BasicVals, unsigned X, - bool isUnsigned); + static NonLoc MakeIntVal(BasicValueFactory& BasicVals, uint64_t X, + bool isUnsigned); static NonLoc MakeVal(BasicValueFactory& BasicVals, uint64_t X, unsigned BitWidth, bool isUnsigned); diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 55c6935b8e..82f4423541 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -114,8 +114,9 @@ QualType ElementRegion::getRValueType(ASTContext& C) const { if (ArrayType* AT = dyn_cast<ArrayType>(T.getTypePtr())) return AT->getElementType(); - PointerType* PtrT = cast<PointerType>(T.getTypePtr()); - return C.getCanonicalType(PtrT->getPointeeType()); + // If the RValueType of the array region isn't an ArrayType, then essentially + // the element's + return T; } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index e50b0abb61..8d36d10a8a 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -403,20 +403,27 @@ SVal RegionStoreManager::getSizeInElements(const GRState* St, const MemRegion* R) { if (const VarRegion* VR = dyn_cast<VarRegion>(R)) { // Get the type of the variable. - QualType T = VR->getRValueType(getContext()); + QualType T = VR->getDesugaredRValueType(getContext()); - // It must be of array type. - const ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr()); - - // return the size as signed integer. - return NonLoc::MakeVal(getBasicVals(), CAT->getSize(), false); + // FIXME: Handle variable-length arrays. + if (isa<VariableArrayType>(T)) + return UnknownVal(); + + if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) { + // return the size as signed integer. + return NonLoc::MakeVal(getBasicVals(), CAT->getSize(), false); + } + + // Clients can use ordinary variables as if they were arrays. These + // essentially are arrays of size 1. + return NonLoc::MakeIntVal(getBasicVals(), 1, false); } if (const StringRegion* SR = dyn_cast<StringRegion>(R)) { const StringLiteral* Str = SR->getStringLiteral(); // We intentionally made the size value signed because it participates in // operations with signed indices. - return NonLoc::MakeVal(getBasicVals(), Str->getByteLength() + 1, false); + return NonLoc::MakeIntVal(getBasicVals(), Str->getByteLength()+1, false); } if (const AnonTypedRegion* ATR = dyn_cast<AnonTypedRegion>(R)) { @@ -880,8 +887,8 @@ const GRState* RegionStoreManager::BindArray(const GRState* St, // When we are binding the whole array, it always has default value 0. GRStateRef state(St, StateMgr); - St = state.set<RegionDefaultValue>(R, NonLoc::MakeVal(getBasicVals(), 0, - false)); + St = state.set<RegionDefaultValue>(R, NonLoc::MakeIntVal(getBasicVals(), 0, + false)); Store store = St->getStore(); @@ -961,8 +968,8 @@ RegionStoreManager::BindStruct(const GRState* St, const TypedRegion* R, SVal V){ // struct decl. In this case, mark the region as having default value. if (VI == VE) { GRStateRef state(St, StateMgr); - St = state.set<RegionDefaultValue>(R, NonLoc::MakeVal(getBasicVals(), 0, - false)); + const NonLoc& Idx = NonLoc::MakeIntVal(getBasicVals(), 0, false); + St = state.set<RegionDefaultValue>(R, Idx); break; } diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index 6847764871..824d7229a3 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -247,10 +247,9 @@ NonLoc NonLoc::MakeVal(SymbolRef sym) { return nonloc::SymbolVal(sym); } -NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, unsigned X, - bool isUnsigned) { - return nonloc::ConcreteInt(BasicVals.getValue(X, sizeof(unsigned)*8, - isUnsigned)); +NonLoc NonLoc::MakeIntVal(BasicValueFactory& BasicVals, uint64_t X, + bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned)); } NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X, diff --git a/test/Analysis/rdar-6541136-region.c b/test/Analysis/rdar-6541136-region.c new file mode 100644 index 0000000000..4fd2214daa --- /dev/null +++ b/test/Analysis/rdar-6541136-region.c @@ -0,0 +1,19 @@ +// RUN: clang -verify -analyze -checker-cfref -analyzer-store-region %s + +struct tea_cheese { unsigned magic; }; +typedef struct tea_cheese kernel_tea_cheese_t; +extern kernel_tea_cheese_t _wonky_gesticulate_cheese; + +// This test case exercises the ElementRegion::getRValueType() logic. + + +void foo( void ) +{ + kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese; + struct load_wine *cmd = (void*) &wonky[1]; + cmd = cmd; + char *p = (void*) &wonky[1]; + *p = 1; + kernel_tea_cheese_t *q = &wonky[1]; + kernel_tea_cheese_t r = *q; // expected-warning{{out-of-bound memory position}} +} diff --git a/test/Analysis/rdar-6541136.c b/test/Analysis/rdar-6541136.c new file mode 100644 index 0000000000..919a21dc21 --- /dev/null +++ b/test/Analysis/rdar-6541136.c @@ -0,0 +1,20 @@ +// clang -verify -analyze -checker-cfref -analyzer-store-basic %s + +struct tea_cheese { unsigned magic; }; +typedef struct tea_cheese kernel_tea_cheese_t; +extern kernel_tea_cheese_t _wonky_gesticulate_cheese; + +// This test case exercises the ElementRegion::getRValueType() logic. +// All it tests is that it does not crash or do anything weird. +// The out-of-bounds-access on line 19 is caught using the region store variant. + +void foo( void ) +{ + kernel_tea_cheese_t *wonky = &_wonky_gesticulate_cheese; + struct load_wine *cmd = (void*) &wonky[1]; + cmd = cmd; + char *p = (void*) &wonky[1]; + *p = 1; + kernel_tea_cheese_t *q = &wonky[1]; + kernel_tea_cheese_t r = *q; // no-warning +} |