Skip to content

Commit 5bc0312

Browse files
committed
Added constaints for pointers: for alignment and size of underlying objects. Fixed type creation for C++ types, fixed tests for types and added for alignment.
1 parent 40e004c commit 5bc0312

23 files changed

+367
-32
lines changed

include/klee/Module/KType.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ class KType {
3636
*/
3737
TypeManager *parent;
3838

39+
/**
40+
* Alignment in bytes for this type.
41+
*/
42+
size_t alignment = 1;
43+
44+
/**
45+
* Size of type.
46+
*/
47+
size_t typeStoreSize = 0;
48+
3949
/**
4050
* Innner types. Maps type to their offsets in current
4151
* type. Should contain type itself and
@@ -73,6 +83,23 @@ class KType {
7383
*/
7484
llvm::Type *getRawType() const;
7585

86+
/**
87+
* Getter for the size.
88+
*/
89+
size_t getSize() const;
90+
91+
/**
92+
* Getter for the alignment.
93+
*/
94+
size_t getAlignment() const;
95+
96+
/**
97+
* Return alignment requirements for that object and
98+
* it subobjects. If no such restrictions can be applied
99+
* returns ref to null expression.
100+
*/
101+
virtual ref<Expr> getContentRestrictions(ref<Expr>) const;
102+
76103
TypeSystemKind getTypeSystemKind() const;
77104

78105
virtual void print(llvm::raw_ostream &) const;

lib/Core/CXXTypeSystem/CXXTypeManager.cpp

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ KType *CXXTypeManager::getWrappedType(llvm::Type *type) {
4444
/* Vector types are considered as their elements type */
4545
llvm::Type *unwrappedRawType = type;
4646
if (unwrappedRawType->isVectorTy()) {
47-
unwrappedRawType = llvm::cast<llvm::VectorType>(unwrappedRawType)->getElementType();
47+
unwrappedRawType =
48+
llvm::cast<llvm::VectorType>(unwrappedRawType)->getElementType();
4849
}
4950

5051
switch (unwrappedRawType->getTypeID()) {
@@ -54,6 +55,10 @@ KType *CXXTypeManager::getWrappedType(llvm::Type *type) {
5455
case (llvm::Type::IntegerTyID):
5556
kt = new cxxtypes::KCXXIntegerType(unwrappedRawType, this);
5657
break;
58+
case (llvm::Type::PPC_FP128TyID):
59+
case (llvm::Type::FP128TyID):
60+
case (llvm::Type::X86_FP80TyID):
61+
case (llvm::Type::DoubleTyID):
5762
case (llvm::Type::FloatTyID):
5863
kt = new cxxtypes::KCXXFloatingPointType(unwrappedRawType, this);
5964
break;
@@ -172,6 +177,38 @@ void CXXTypeManager::onFinishInitModule() {
172177
}
173178
}
174179

180+
/**
181+
* Util method to create constraints for pointers
182+
* for complex structures that can have many types located
183+
* by different offsets.
184+
*/
185+
static ref<Expr> getComplexPointerRestrictions(
186+
ref<Expr> object,
187+
const std::vector<std::pair<size_t, KType *>> &offsetsToTypes) {
188+
ref<Expr> resultCondition;
189+
for (auto &offsetToTypePair : offsetsToTypes) {
190+
size_t offset = offsetToTypePair.first;
191+
KType *extractedType = offsetToTypePair.second;
192+
193+
ref<Expr> extractedOffset = ExtractExpr::create(
194+
object, offset * CHAR_BIT, extractedType->getSize() * CHAR_BIT);
195+
ref<Expr> innerAlignmentRequirement =
196+
llvm::cast<cxxtypes::KCXXType>(extractedType)
197+
->getPointersRestrictions(extractedOffset);
198+
if (innerAlignmentRequirement.isNull()) {
199+
continue;
200+
}
201+
202+
if (resultCondition.isNull()) {
203+
resultCondition = innerAlignmentRequirement;
204+
} else {
205+
resultCondition =
206+
AndExpr::create(resultCondition, innerAlignmentRequirement);
207+
}
208+
}
209+
return resultCondition;
210+
}
211+
175212
/* C++ KType base class */
176213
cxxtypes::KCXXType::KCXXType(llvm::Type *type, TypeManager *parent)
177214
: KType(type, parent) {
@@ -193,6 +230,19 @@ bool cxxtypes::KCXXType::isAccessableFrom(KType *accessingType) const {
193230
assert(false && "Attempted to compare raw llvm type with C++ type!");
194231
}
195232

233+
ref<Expr> cxxtypes::KCXXType::getContentRestrictions(ref<Expr> object) const {
234+
if (type == nullptr) {
235+
return nullptr;
236+
}
237+
llvm::Type *elementType = type->getPointerElementType();
238+
return llvm::cast<cxxtypes::KCXXType>(parent->getWrappedType(elementType))
239+
->getPointersRestrictions(object);
240+
}
241+
242+
ref<Expr> cxxtypes::KCXXType::getPointersRestrictions(ref<Expr>) const {
243+
return nullptr;
244+
}
245+
196246
bool cxxtypes::KCXXType::isAccessingFromChar(KCXXType *accessingType) {
197247
/* Special case for unknown type */
198248
if (accessingType->getRawType() == nullptr) {
@@ -231,6 +281,19 @@ cxxtypes::KCXXCompositeType::KCXXCompositeType(KType *type, TypeManager *parent,
231281
insertedTypes.emplace(type);
232282
}
233283

284+
ref<Expr>
285+
cxxtypes::KCXXCompositeType::getPointersRestrictions(ref<Expr> object) const {
286+
if (containsSymbolic) {
287+
return nullptr;
288+
}
289+
std::vector<std::pair<size_t, KType *>> offsetToTypes;
290+
for (auto &offsetToTypePair : typesLocations) {
291+
offsetToTypes.emplace_back(offsetToTypePair.first,
292+
offsetToTypePair.second.first);
293+
}
294+
return getComplexPointerRestrictions(object, offsetToTypes);
295+
}
296+
234297
void cxxtypes::KCXXCompositeType::handleMemoryAccess(KType *type,
235298
ref<Expr> offset,
236299
ref<Expr> size,
@@ -411,6 +474,21 @@ cxxtypes::KCXXStructType::KCXXStructType(llvm::Type *type, TypeManager *parent)
411474
}
412475
}
413476

477+
ref<Expr>
478+
cxxtypes::KCXXStructType::getPointersRestrictions(ref<Expr> object) const {
479+
std::vector<std::pair<size_t, KType *>> offsetsToTypes;
480+
for (auto &innerTypeToOffsets : innerTypes) {
481+
KType *innerType = innerTypeToOffsets.first;
482+
if (!llvm::isa<KCXXPointerType>(innerType)) {
483+
continue;
484+
}
485+
for (auto &offset : innerTypeToOffsets.second) {
486+
offsetsToTypes.emplace_back(offset, innerType);
487+
}
488+
}
489+
return getComplexPointerRestrictions(object, offsetsToTypes);
490+
}
491+
414492
bool cxxtypes::KCXXStructType::isAccessableFrom(KCXXType *accessingType) const {
415493
/* FIXME: this is a temporary hack for vtables in C++. Ideally, we
416494
* should demangle global variables to get additional info, at least
@@ -460,6 +538,15 @@ cxxtypes::KCXXArrayType::KCXXArrayType(llvm::Type *type, TypeManager *parent)
460538
arrayElementsCount = rawArrayType->getArrayNumElements();
461539
}
462540

541+
ref<Expr>
542+
cxxtypes::KCXXArrayType::getPointersRestrictions(ref<Expr> object) const {
543+
std::vector<std::pair<size_t, KType *>> offsetsToTypes;
544+
for (unsigned idx = 0; idx < arrayElementsCount; ++idx) {
545+
offsetsToTypes.emplace_back(idx * elementType->getSize(), elementType);
546+
}
547+
return getComplexPointerRestrictions(object, offsetsToTypes);
548+
}
549+
463550
bool cxxtypes::KCXXArrayType::isAccessableFrom(KCXXType *accessingType) const {
464551
if (llvm::isa<KCXXArrayType>(accessingType)) {
465552
return innerIsAccessableFrom(llvm::cast<KCXXArrayType>(accessingType));
@@ -575,6 +662,26 @@ bool cxxtypes::KCXXPointerType::innerIsAccessableFrom(
575662
return accessingType->getRawType() == nullptr;
576663
}
577664

665+
ref<Expr>
666+
cxxtypes::KCXXPointerType::getPointersRestrictions(ref<Expr> object) const {
667+
/**
668+
* We assume that alignment is always a power of 2 and has
669+
* a bit representation as 00...010...00. By subtracting 1
670+
* we are getting 00...011...1. Then we apply this mask to
671+
* address and require, that bitwise AND should give 0 (i.e.
672+
* non of the last bits is 1).
673+
*/
674+
ref<Expr> appliedAlignmentMask = AndExpr::create(
675+
Expr::createPointer(elementType->getAlignment() - 1), object);
676+
677+
ref<Expr> sizeExpr = Expr::createPointer(elementType->getSize() - 1);
678+
679+
ref<Expr> objectUpperBound = AddExpr::create(object, sizeExpr);
680+
681+
return AndExpr::create(Expr::createIsZero(appliedAlignmentMask),
682+
UgeExpr::create(objectUpperBound, sizeExpr));
683+
}
684+
578685
bool cxxtypes::KCXXPointerType::innerIsAccessableFrom(
579686
KCXXPointerType *accessingType) const {
580687
return elementType->isAccessableFrom(accessingType->elementType);

lib/Core/CXXTypeSystem/CXXTypeManager.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class KCXXType : public KType {
9191
virtual bool isAccessableFrom(KType *) const final override;
9292
virtual bool isAccessableFrom(KCXXType *) const;
9393

94+
virtual ref<Expr> getContentRestrictions(ref<Expr>) const override;
95+
virtual ref<Expr> getPointersRestrictions(ref<Expr>) const;
96+
9497
CXXTypeKind getTypeKind() const;
9598

9699
static bool classof(const KType *);
@@ -115,6 +118,7 @@ class KCXXCompositeType : public KCXXType {
115118
KCXXCompositeType(KType *, TypeManager *, ref<Expr>);
116119

117120
public:
121+
virtual ref<Expr> getPointersRestrictions(ref<Expr>) const override;
118122
virtual void handleMemoryAccess(KType *, ref<Expr>, ref<Expr> size,
119123
bool isWrite) override;
120124
virtual bool isAccessableFrom(KCXXType *) const override;
@@ -137,6 +141,7 @@ class KCXXStructType : public KCXXType {
137141
KCXXStructType(llvm::Type *, TypeManager *);
138142

139143
public:
144+
virtual ref<Expr> getPointersRestrictions(ref<Expr>) const override;
140145
virtual bool isAccessableFrom(KCXXType *) const override;
141146

142147
static bool classof(const KType *);
@@ -224,6 +229,7 @@ class KCXXArrayType : public KCXXType {
224229
KCXXArrayType(llvm::Type *, TypeManager *);
225230

226231
public:
232+
virtual ref<Expr> getPointersRestrictions(ref<Expr>) const override;
227233
virtual bool isAccessableFrom(KCXXType *) const override;
228234

229235
static bool classof(const KType *);
@@ -245,7 +251,9 @@ class KCXXPointerType : public KCXXType {
245251
KCXXPointerType(llvm::Type *, TypeManager *);
246252

247253
public:
254+
virtual ref<Expr> getPointersRestrictions(ref<Expr>) const override;
248255
virtual bool isAccessableFrom(KCXXType *) const override;
256+
249257
bool isPointerToChar() const;
250258
bool isPointerToFunction() const;
251259

lib/Core/Executor.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ cl::opt<bool>
159159
cl::desc("Turns on restrictions based on types compatibility for "
160160
"symbolic pointers (default=false)"),
161161
cl::init(false));
162+
163+
cl::opt<bool>
164+
AlignSymbolicPointers("align-symbolic-pointers",
165+
cl::desc("Makes symbolic pointers aligned according"
166+
"to the used type system (default=true)"),
167+
cl::init(true));
162168
} // namespace klee
163169

164170
namespace {
@@ -5002,7 +5008,19 @@ void Executor::executeMemoryOperation(ExecutionState &state,
50025008
if (!unbound)
50035009
break;
50045010
}
5005-
5011+
5012+
5013+
if (unbound) {
5014+
StatePair branches =
5015+
fork(*unbound, Expr::createIsZero(base), true, BranchType::MemOp);
5016+
ExecutionState *bound = branches.first;
5017+
if (bound) {
5018+
terminateStateOnError(*bound, "memory error: null pointer exception",
5019+
StateTerminationType::Ptr);
5020+
}
5021+
unbound = branches.second;
5022+
}
5023+
50065024
// XXX should we distinguish out of bounds and overlapped cases?
50075025
if (unbound) {
50085026
if (incomplete) {
@@ -5122,7 +5140,15 @@ void Executor::executeMakeSymbolic(ExecutionState &state,
51225140
const Array *array = makeArray(state, mo->size, name);
51235141
const_cast<Array*>(array)->binding = mo;
51245142
const_cast<MemoryObject *>(mo)->isKleeMakeSymbolic = true;
5125-
bindObjectInState(state, mo, type, isLocal, array);
5143+
ObjectState *os = bindObjectInState(state, mo, type, isLocal, array);
5144+
5145+
if (AlignSymbolicPointers) {
5146+
if (ref<Expr> alignmentRestrictions =
5147+
type->getContentRestrictions(os->read(0, os->size * CHAR_BIT))) {
5148+
addConstraint(state, alignmentRestrictions);
5149+
}
5150+
}
5151+
51265152
state.addSymbolic(mo, array);
51275153

51285154
std::map< ExecutionState*, std::vector<SeedInfo> >::iterator it =

lib/Core/TypeManager.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void TypeManager::initTypesFromStructs() {
9292
dfs(structType);
9393
}
9494

95-
for (auto structType : sortedStructTypesGraph) {
95+
for (auto structType : sortedStructTypesGraph) {
9696
if (structType->isOpaque()) {
9797
continue;
9898
}
@@ -160,6 +160,16 @@ void TypeManager::initTypesFromInstructions() {
160160
}
161161
}
162162

163+
void TypeManager::initTypeInfo() {
164+
for (auto &type : types) {
165+
llvm::Type *rawType = type->getRawType();
166+
if (rawType && rawType->isSized()) {
167+
type->alignment = parent->targetData->getABITypeAlignment(rawType);
168+
type->typeStoreSize = parent->targetData->getTypeStoreSize(rawType);
169+
}
170+
}
171+
}
172+
163173
void TypeManager::onFinishInitModule() {}
164174

165175
/**
@@ -174,5 +184,6 @@ void TypeManager::initModule() {
174184
initTypesFromGlobals();
175185
initTypesFromInstructions();
176186
initTypesFromStructs();
187+
initTypeInfo();
177188
onFinishInitModule();
178189
}

lib/Core/TypeManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class TypeManager {
3030
void initTypesFromGlobals();
3131
void initTypesFromStructs();
3232
void initTypesFromInstructions();
33+
void initTypeInfo();
3334

3435
protected:
3536
KModule *parent;

lib/Module/KType.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ bool KType::isAccessableFrom(KType *accessingType) const { return true; }
2424

2525
llvm::Type *KType::getRawType() const { return type; }
2626

27-
TypeSystemKind KType::getTypeSystemKind() const {
28-
return typeSystemKind;
29-
}
27+
TypeSystemKind KType::getTypeSystemKind() const { return typeSystemKind; }
3028

3129
void KType::handleMemoryAccess(KType *, ref<Expr>, ref<Expr>, bool isWrite) {}
3230

31+
size_t KType::getSize() const { return typeStoreSize; }
32+
33+
size_t KType::getAlignment() const { return alignment; }
34+
35+
ref<Expr> KType::getContentRestrictions(ref<Expr>) const { return nullptr; }
36+
3337
void KType::print(llvm::raw_ostream &os) const {
3438
if (type == nullptr) {
3539
os << "nullptr";
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang %s -emit-llvm -g -c -o %t.bc
2+
// RUN: rm -rf %t.klee-out
3+
// RUN: %klee --output-dir=%t.klee-out --use-gep-expr %t.bc 2>&1 | FileCheck %s
4+
5+
#include "klee/klee.h"
6+
7+
int main() {
8+
int *ptr;
9+
klee_make_symbolic(&ptr, sizeof(ptr), "ptr");
10+
// CHECK: NullPointerDereferenceCheck.c:[[@LINE+1]]: memory error: null pointer exception
11+
*ptr = 10;
12+
}

0 commit comments

Comments
 (0)