Skip to content

Commit

Permalink
[feat] Uninitialized Memory [feat] Sizeless ObjectState
Browse files Browse the repository at this point in the history
[feat] STP and MetaSMT symsize array support
  • Loading branch information
ocelaiwo authored and misonijnik committed Oct 21, 2023
1 parent d5ff4df commit c3553c0
Show file tree
Hide file tree
Showing 83 changed files with 4,973 additions and 1,175 deletions.
1 change: 1 addition & 0 deletions include/klee/ADT/KTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct KTest {

unsigned numObjects;
KTestObject *objects;
unsigned uninitCoeff;
};

/* returns the current .ktest file format version */
Expand Down
13 changes: 13 additions & 0 deletions include/klee/ADT/Ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,19 @@ template <class T> class ref {
bool operator!=(const ref &rhs) const { return !equals(rhs); }
};

template <typename T> class OptionalRefEq {
public:
bool operator()(const ref<T> &lhs, const ref<T> &rhs) {
if (lhs.isNull() && rhs.isNull()) {
return true;
}
if (lhs.isNull() || rhs.isNull()) {
return false;
}
return lhs.get()->equals(*rhs.get());
}
};

template <class T>
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ref<T> &e) {
os << *e;
Expand Down
145 changes: 80 additions & 65 deletions include/klee/ADT/SparseStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,67 +3,56 @@

#include <cassert>
#include <cstddef>
#include <functional>
#include <iterator>
#include <map>
#include <unordered_map>
#include <vector>

namespace llvm {
class raw_ostream;
};

namespace klee {

template <typename ValueType> class SparseStorage {
enum class Density {
Sparse,
Dense,
};

template <typename ValueType, typename Eq = std::equal_to<ValueType>>
class SparseStorage {
private:
size_t capacity;
std::map<size_t, ValueType> internalStorage;
std::unordered_map<size_t, ValueType> internalStorage;
ValueType defaultValue;
Eq eq;

bool contains(size_t key) const { return internalStorage.count(key) != 0; }

public:
struct Iterator {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = ValueType;
using pointer = ValueType *;
using reference = ValueType &;

private:
size_t idx;
const SparseStorage *owner;

public:
Iterator(size_t idx, const SparseStorage *owner) : idx(idx), owner(owner) {}

value_type operator*() const { return owner->load(idx); }

Iterator &operator++() {
++idx;
return *this;
}

Iterator operator++(int) {
Iterator snap = *this;
++(*this);
return snap;
SparseStorage(const ValueType &defaultValue = ValueType())
: defaultValue(defaultValue) {}

SparseStorage(const std::unordered_map<size_t, ValueType> &internalStorage,
const ValueType &defaultValue)
: defaultValue(defaultValue) {
for (auto &[index, value] : internalStorage) {
store(index, value);
}

bool operator==(const Iterator &other) const { return idx == other.idx; }

bool operator!=(const Iterator &other) const { return !(*this == other); }
};

SparseStorage(size_t capacity = 0,
const ValueType &defaultValue = ValueType())
: capacity(capacity), defaultValue(defaultValue) {}
}

SparseStorage(const std::vector<ValueType> &values,
const ValueType &defaultValue = ValueType())
: capacity(values.capacity()), defaultValue(defaultValue) {
for (size_t idx = 0; idx < values.capacity(); ++idx) {
internalStorage[idx] = values[idx];
: defaultValue(defaultValue) {
for (size_t idx = 0; idx < values.size(); ++idx) {
store(idx, values[idx]);
}
}

void store(size_t idx, const ValueType &value) {
if (idx < capacity) {
if (eq(value, defaultValue)) {
internalStorage.erase(idx);
} else {
internalStorage[idx] = value;
}
}
Expand All @@ -77,55 +66,81 @@ template <typename ValueType> class SparseStorage {
}

ValueType load(size_t idx) const {
assert(idx < capacity && idx >= 0);
return contains(idx) ? internalStorage.at(idx) : defaultValue;
}

size_t size() const { return capacity; }

void resize(size_t newCapacity) {
assert(newCapacity >= 0);
// Free to extend
if (newCapacity >= capacity) {
capacity = newCapacity;
return;
}

// Truncate unnessecary elements
auto iterOnNewSize = internalStorage.lower_bound(newCapacity);
while (iterOnNewSize != internalStorage.end()) {
iterOnNewSize = internalStorage.erase(iterOnNewSize);
size_t sizeOfSetRange() const {
size_t sizeOfRange = 0;
for (auto i : internalStorage) {
sizeOfRange = std::max(i.first, sizeOfRange);
}

capacity = newCapacity;
return sizeOfRange;
}

bool operator==(const SparseStorage<ValueType> &another) const {
return size() == another.size() && defaultValue == another.defaultValue &&
internalStorage == another.internalStorage;
return defaultValue == another.defaultValue && compare(another) == 0;
}

bool operator!=(const SparseStorage<ValueType> &another) const {
return !(*this == another);
}

bool operator<(const SparseStorage &another) const {
return internalStorage < another.internalStorage;
return compare(another) == -1;
}

bool operator>(const SparseStorage &another) const {
return internalStorage > another.internalStorage;
return compare(another) == 1;
}

int compare(const SparseStorage<ValueType> &other) const {
auto ordered = calculateOrderedStorage();
auto otherOrdered = other.calculateOrderedStorage();

if (ordered == otherOrdered) {
return 0;
} else {
return ordered < otherOrdered ? -1 : 1;
}
}

std::map<size_t, ValueType> calculateOrderedStorage() const {
std::map<size_t, ValueType> ordered;
for (const auto &i : internalStorage) {
ordered.insert(i);
}
return ordered;
}

std::vector<ValueType> getFirstNIndexes(size_t n) const {
std::vector<ValueType> vectorized(n);
for (size_t i = 0; i < n; i++) {
vectorized[i] = load(i);
}
return vectorized;
}

const std::unordered_map<size_t, ValueType> &storage() const {
return internalStorage;
};

const ValueType &defaultV() const { return defaultValue; };

void reset() { internalStorage.clear(); }

void reset(ValueType newDefault) {
defaultValue = newDefault;
internalStorage.clear();
}

Iterator begin() const { return Iterator(0, this); }
Iterator end() const { return Iterator(size(), this); }
void print(llvm::raw_ostream &os, Density) const;
};

template <typename U>
SparseStorage<unsigned char> sparseBytesFromValue(const U &value) {
const unsigned char *valueUnsignedCharIterator =
reinterpret_cast<const unsigned char *>(&value);
SparseStorage<unsigned char> result(sizeof(value));
SparseStorage<unsigned char> result;
result.store(0, valueUnsignedCharIterator,
valueUnsignedCharIterator + sizeof(value));
return result;
Expand Down
5 changes: 2 additions & 3 deletions include/klee/Expr/ArrayCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ class ArrayCache {
klee::EquivArrayCmpFn>
ArrayHashSet;
ArrayHashSet cachedSymbolicArrays;
typedef std::vector<const Array *> ArrayPtrVec;
ArrayPtrVec concreteArrays;

unsigned getNextID() const;
// Number of arrays of each source allocated
std::unordered_map<SymbolicSource::Kind, unsigned> allocatedCount;
};
} // namespace klee

Expand Down
4 changes: 3 additions & 1 deletion include/klee/Expr/Assignment.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ class AssignmentEvaluator : public ExprEvaluator {
inline ref<Expr> Assignment::evaluate(const Array *array, unsigned index,
bool allowFreeValues) const {
assert(array);
auto sizeExpr = evaluate(array->size);
bindings_ty::iterator it = bindings.find(array);
if (it != bindings.end() && index < it->second.size()) {
if (it != bindings.end() && isa<ConstantExpr>(sizeExpr) &&
index < cast<ConstantExpr>(sizeExpr)->getZExtValue()) {
return ConstantExpr::alloc(it->second.load(index), array->getRange());
} else {
if (allowFreeValues) {
Expand Down
7 changes: 2 additions & 5 deletions include/klee/Expr/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ struct Expr::CreateArg {
// Comparison operators

inline bool operator==(const Expr &lhs, const Expr &rhs) {
return lhs.compare(rhs) == 0;
return lhs.equals(rhs);
}

inline bool operator<(const Expr &lhs, const Expr &rhs) {
Expand Down Expand Up @@ -636,10 +636,7 @@ class Array {

public:
bool isSymbolicArray() const { return !isConstantArray(); }
bool isConstantArray() const {
return isa<ConstantSource>(source) ||
isa<SymbolicSizeConstantSource>(source);
}
bool isConstantArray() const { return isa<ConstantSource>(source); }

const std::string getName() const { return source->toString(); }
const std::string getIdentifier() const {
Expand Down
2 changes: 2 additions & 0 deletions include/klee/Expr/Parser/Lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ struct Token {
KWFalse, ///< 'false'
KWQuery, ///< 'query'
KWPath, ///< 'path'
KWDefault, ///< 'default'
KWNull, ///< 'null'
KWReserved, ///< fp[0-9]+([.].*)?, i[0-9]+
KWSymbolic, ///< 'symbolic'
KWTrue, ///< 'true'
Expand Down
12 changes: 8 additions & 4 deletions include/klee/Expr/SourceBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define KLEE_SOURCEBUILDER_H

#include "klee/ADT/Ref.h"
#include "klee/ADT/SparseStorage.h"
#include "klee/Expr/SymbolicSource.h"
#include "klee/Module/KModule.h"

Expand All @@ -12,10 +13,13 @@ class SourceBuilder {
SourceBuilder() = delete;

static ref<SymbolicSource>
constant(const std::vector<ref<ConstantExpr>> &constantValues);
static ref<SymbolicSource> symbolicSizeConstant(unsigned defaultValue);
static ref<SymbolicSource> symbolicSizeConstantAddress(unsigned defaultValue,
unsigned version);
constant(SparseStorage<ref<ConstantExpr>> constantValues);

static ref<SymbolicSource> uninitialized(unsigned version,
const KInstruction *allocSite);
static ref<SymbolicSource>
symbolicSizeConstantAddress(unsigned version, const KInstruction *allocSite,
ref<Expr> size);
static ref<SymbolicSource> makeSymbolic(const std::string &name,
unsigned version);
static ref<SymbolicSource> lazyInitializationAddress(ref<Expr> pointer);
Expand Down
Loading

0 comments on commit c3553c0

Please sign in to comment.