Skip to content

Commit b136bee

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 b136bee

23 files changed

+379
-33
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: 119 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;
@@ -193,6 +198,19 @@ bool cxxtypes::KCXXType::isAccessableFrom(KType *accessingType) const {
193198
assert(false && "Attempted to compare raw llvm type with C++ type!");
194199
}
195200

201+
ref<Expr> cxxtypes::KCXXType::getContentRestrictions(ref<Expr> object) const {
202+
if (type == nullptr) {
203+
return nullptr;
204+
}
205+
llvm::Type *elementType = type->getPointerElementType();
206+
return llvm::cast<cxxtypes::KCXXType>(parent->getWrappedType(elementType))
207+
->getPointersRestrictions(object);
208+
}
209+
210+
ref<Expr> cxxtypes::KCXXType::getPointersRestrictions(ref<Expr>) const {
211+
return nullptr;
212+
}
213+
196214
bool cxxtypes::KCXXType::isAccessingFromChar(KCXXType *accessingType) {
197215
/* Special case for unknown type */
198216
if (accessingType->getRawType() == nullptr) {
@@ -231,6 +249,35 @@ cxxtypes::KCXXCompositeType::KCXXCompositeType(KType *type, TypeManager *parent,
231249
insertedTypes.emplace(type);
232250
}
233251

252+
ref<Expr>
253+
cxxtypes::KCXXCompositeType::getPointersRestrictions(ref<Expr> object) const {
254+
if (containsSymbolic) {
255+
return nullptr;
256+
}
257+
258+
ref<Expr> result = nullptr;
259+
for (auto &offsetToType : typesLocations) {
260+
size_t offset = offsetToType.first;
261+
KType *extractedType = offsetToType.second.first;
262+
263+
ref<Expr> extractedOffset = ExtractExpr::create(
264+
object, offset * CHAR_BIT, extractedType->getSize() * CHAR_BIT);
265+
ref<Expr> innerAlignmentRequirement =
266+
llvm::cast<KCXXType>(extractedType)
267+
->getPointersRestrictions(extractedOffset);
268+
if (innerAlignmentRequirement.isNull()) {
269+
continue;
270+
}
271+
272+
if (result.isNull()) {
273+
result = innerAlignmentRequirement;
274+
} else {
275+
result = AndExpr::create(result, innerAlignmentRequirement);
276+
}
277+
}
278+
return result;
279+
}
280+
234281
void cxxtypes::KCXXCompositeType::handleMemoryAccess(KType *type,
235282
ref<Expr> offset,
236283
ref<Expr> size,
@@ -411,6 +458,35 @@ cxxtypes::KCXXStructType::KCXXStructType(llvm::Type *type, TypeManager *parent)
411458
}
412459
}
413460

461+
ref<Expr>
462+
cxxtypes::KCXXStructType::getPointersRestrictions(ref<Expr> object) const {
463+
ref<Expr> result = nullptr;
464+
for (auto &innerTypeToOffsets : innerTypes) {
465+
KType *innerType = innerTypeToOffsets.first;
466+
if (!llvm::isa<KCXXPointerType>(innerType)) {
467+
continue;
468+
}
469+
for (auto offset : innerTypeToOffsets.second) {
470+
ref<Expr> extractedExpr = ExtractExpr::create(
471+
object, offset * CHAR_BIT, innerType->getSize() * CHAR_BIT);
472+
473+
ref<Expr> innerAlignmentRequirement =
474+
llvm::cast<KCXXType>(innerType)->getPointersRestrictions(
475+
extractedExpr);
476+
if (innerAlignmentRequirement.isNull()) {
477+
continue;
478+
}
479+
480+
if (result.isNull()) {
481+
result = innerAlignmentRequirement;
482+
} else {
483+
result = AndExpr::create(result, innerAlignmentRequirement);
484+
}
485+
}
486+
}
487+
return result;
488+
}
489+
414490
bool cxxtypes::KCXXStructType::isAccessableFrom(KCXXType *accessingType) const {
415491
/* FIXME: this is a temporary hack for vtables in C++. Ideally, we
416492
* should demangle global variables to get additional info, at least
@@ -460,6 +536,28 @@ cxxtypes::KCXXArrayType::KCXXArrayType(llvm::Type *type, TypeManager *parent)
460536
arrayElementsCount = rawArrayType->getArrayNumElements();
461537
}
462538

539+
ref<Expr>
540+
cxxtypes::KCXXArrayType::getPointersRestrictions(ref<Expr> object) const {
541+
ref<Expr> result = nullptr;
542+
for (unsigned idx = 0; idx < arrayElementsCount; ++idx) {
543+
ref<Expr> extractedExpr =
544+
ExtractExpr::create(object, idx * elementType->getSize() * CHAR_BIT,
545+
elementType->getSize() * CHAR_BIT);
546+
ref<Expr> innerAlignmentRequirement =
547+
elementType->getPointersRestrictions(extractedExpr);
548+
if (innerAlignmentRequirement.isNull()) {
549+
continue;
550+
}
551+
552+
if (result.isNull()) {
553+
result = innerAlignmentRequirement;
554+
} else {
555+
result = AndExpr::create(result, innerAlignmentRequirement);
556+
}
557+
}
558+
return result;
559+
}
560+
463561
bool cxxtypes::KCXXArrayType::isAccessableFrom(KCXXType *accessingType) const {
464562
if (llvm::isa<KCXXArrayType>(accessingType)) {
465563
return innerIsAccessableFrom(llvm::cast<KCXXArrayType>(accessingType));
@@ -575,6 +673,26 @@ bool cxxtypes::KCXXPointerType::innerIsAccessableFrom(
575673
return accessingType->getRawType() == nullptr;
576674
}
577675

676+
ref<Expr>
677+
cxxtypes::KCXXPointerType::getPointersRestrictions(ref<Expr> object) const {
678+
/**
679+
* We assume that alignment is always a power of 2 and has
680+
* a bit representation as 00...010...00. By subtracting 1
681+
* we are getting 00...011...1. Then we apply this mask to
682+
* address and require, that bitwise AND should give 0 (i.e.
683+
* non of the last bits is 1).
684+
*/
685+
ref<Expr> appliedAlignmentMask = AndExpr::create(
686+
Expr::createPointer(elementType->getAlignment() - 1), object);
687+
688+
ref<Expr> sizeExpr = Expr::createPointer(elementType->getSize() - 1);
689+
690+
ref<Expr> objectUpperBound = AddExpr::create(object, sizeExpr);
691+
692+
return AndExpr::create(Expr::createIsZero(appliedAlignmentMask),
693+
UgeExpr::create(objectUpperBound, sizeExpr));
694+
}
695+
578696
bool cxxtypes::KCXXPointerType::innerIsAccessableFrom(
579697
KCXXPointerType *accessingType) const {
580698
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: 29 additions & 3 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 {
@@ -4932,7 +4938,7 @@ void Executor::executeMemoryOperation(ExecutionState &state,
49324938

49334939
// XXX there is some query wasteage here. who cares?
49344940
ExecutionState *unbound = &state;
4935-
4941+
49364942
for (ResolutionList::iterator i = rl.begin(), ie = rl.end(); i != ie; ++i) {
49374943
const MemoryObject *mo = i->first;
49384944
const ObjectState *os = i->second;
@@ -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)