aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Analysis/PathSensitive/BasicValueFactory.h5
-rw-r--r--include/clang/Analysis/PathSensitive/MemRegion.h8
-rw-r--r--include/clang/Analysis/PathSensitive/SVals.h4
-rw-r--r--lib/Analysis/MemRegion.cpp5
-rw-r--r--lib/Analysis/RegionStore.cpp29
-rw-r--r--lib/Analysis/SVals.cpp7
-rw-r--r--test/Analysis/rdar-6541136-region.c19
-rw-r--r--test/Analysis/rdar-6541136.c20
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
+}