diff options
-rw-r--r-- | lib/Core/Executor.cpp | 96 | ||||
-rw-r--r-- | lib/Core/Executor.h | 1 | ||||
-rw-r--r-- | lib/Core/MemoryManager.h | 2 | ||||
-rw-r--r-- | test/regression/2016-12-14-alloc-alignment.c | 21 |
4 files changed, 110 insertions, 10 deletions
diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 19a5e3f8..d8a4a32c 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -44,6 +44,7 @@ #include "klee/Internal/Module/KModule.h" #include "klee/Internal/Support/ErrorHandling.h" #include "klee/Internal/Support/FloatEvaluation.h" +#include "klee/Internal/Support/ModuleUtil.h" #include "klee/Internal/System/Time.h" #include "klee/Internal/System/MemoryUsage.h" #include "klee/SolverStats.h" @@ -592,6 +593,7 @@ void Executor::initializeGlobals(ExecutionState &state) { for (Module::const_global_iterator i = m->global_begin(), e = m->global_end(); i != e; ++i) { + size_t globalObjectAlignment = getAllocationAlignment(i); if (i->isDeclaration()) { // FIXME: We have no general way of handling unknown external // symbols. If we really cared about making external stuff work @@ -623,7 +625,9 @@ void Executor::initializeGlobals(ExecutionState &state) { (int)i->getName().size(), i->getName().data()); } - MemoryObject *mo = memory->allocate(size, false, true, i); + MemoryObject *mo = memory->allocate(size, /*isLocal=*/false, + /*isGlobal=*/true, /*allocSite=*/i, + /*alignment=*/globalObjectAlignment); ObjectState *os = bindObjectInState(state, mo, false); globalObjects.insert(std::make_pair(i, mo)); globalAddresses.insert(std::make_pair(i, mo->getBaseExpr())); @@ -647,7 +651,9 @@ void Executor::initializeGlobals(ExecutionState &state) { } else { LLVM_TYPE_Q Type *ty = i->getType()->getElementType(); uint64_t size = kmodule->targetData->getTypeStoreSize(ty); - MemoryObject *mo = memory->allocate(size, false, true, &*i); + MemoryObject *mo = memory->allocate(size, /*isLocal=*/false, + /*isGlobal=*/true, /*allocSite=*/&*i, + /*alignment=*/globalObjectAlignment); if (!mo) llvm::report_fatal_error("out of memory"); ObjectState *os = bindObjectInState(state, mo, false); @@ -3149,8 +3155,11 @@ void Executor::executeAlloc(ExecutionState &state, const ObjectState *reallocFrom) { size = toUnique(state, size); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(size)) { - MemoryObject *mo = memory->allocate(CE->getZExtValue(), isLocal, false, - state.prevPC->inst); + const llvm::Value *allocSite = state.prevPC->inst; + size_t allocationAlignment = getAllocationAlignment(allocSite); + MemoryObject *mo = + memory->allocate(CE->getZExtValue(), isLocal, /*isGlobal=*/false, + allocSite, allocationAlignment); if (!mo) { bindLocal(target, state, ConstantExpr::alloc(0, Context::get().getPointerWidth())); @@ -3533,10 +3542,11 @@ void Executor::runFunctionAsMain(Function *f, Function::arg_iterator ai = f->arg_begin(), ae = f->arg_end(); if (ai!=ae) { arguments.push_back(ConstantExpr::alloc(argc, Expr::Int32)); - if (++ai!=ae) { - argvMO = memory->allocate((argc+1+envc+1+1) * NumPtrBytes, false, true, - f->begin()->begin()); + argvMO = + memory->allocate((argc + 1 + envc + 1 + 1) * NumPtrBytes, + /*isLocal=*/false, /*isGlobal=*/true, + /*allocSite=*/f->begin()->begin(), /*alignment=*/8); if (!argvMO) klee_error("Could not allocate memory for function arguments"); @@ -3578,8 +3588,10 @@ void Executor::runFunctionAsMain(Function *f, } else { char *s = i<argc ? argv[i] : envp[i-(argc+1)]; int j, len = strlen(s); - - MemoryObject *arg = memory->allocate(len+1, false, true, state->pc->inst); + + MemoryObject *arg = + memory->allocate(len + 1, /*isLocal=*/false, /*isGlobal=*/true, + /*allocSite=*/state->pc->inst, /*alignment=*/8); if (!arg) klee_error("Could not allocate memory for function arguments"); ObjectState *os = bindObjectInState(*state, arg, false); @@ -3755,6 +3767,72 @@ Expr::Width Executor::getWidthForLLVMType(LLVM_TYPE_Q llvm::Type *type) const { return kmodule->targetData->getTypeSizeInBits(type); } +size_t Executor::getAllocationAlignment(const llvm::Value *allocSite) const { + // FIXME: 8 was the previous default. We shouldn't hard code this + // and should fetch the default from elsewhere. + const size_t forcedAlignment = 8; + size_t alignment = 0; + LLVM_TYPE_Q llvm::Type *type = NULL; + std::string allocationSiteName(allocSite->getName().str()); + if (const GlobalValue *GV = dyn_cast<GlobalValue>(allocSite)) { + alignment = GV->getAlignment(); + if (const GlobalVariable *globalVar = dyn_cast<GlobalVariable>(GV)) { + // All GlobalVariables's have pointer type + LLVM_TYPE_Q llvm::PointerType *ptrType = + dyn_cast<llvm::PointerType>(globalVar->getType()); + assert(ptrType && "globalVar's type is not a pointer"); + type = ptrType->getElementType(); + } else { + type = GV->getType(); + } + } else if (const AllocaInst *AI = dyn_cast<AllocaInst>(allocSite)) { + alignment = AI->getAlignment(); + type = AI->getAllocatedType(); + } else if (isa<InvokeInst>(allocSite) || isa<CallInst>(allocSite)) { + // FIXME: Model the semantics of the call to use the right alignment + llvm::Value *allocSiteNonConst = const_cast<llvm::Value *>(allocSite); + const CallSite cs = (isa<InvokeInst>(allocSiteNonConst) + ? CallSite(cast<InvokeInst>(allocSiteNonConst)) + : CallSite(cast<CallInst>(allocSiteNonConst))); + llvm::Function *fn = + klee::getDirectCallTarget(cs, /*moduleIsFullyLinked=*/true); + if (fn) + allocationSiteName = fn->getName().str(); + + klee_warning_once(fn != NULL ? fn : allocSite, + "Alignment of memory from call \"%s\" is not " + "modelled. Using alignment of %zu.", + allocationSiteName.c_str(), forcedAlignment); + alignment = forcedAlignment; + } else { + llvm_unreachable("Unhandled allocation site"); + } + + if (alignment == 0) { + assert(type != NULL); + // No specified alignment. Get the alignment for the type. + if (type->isSized()) { + alignment = kmodule->targetData->getPrefTypeAlignment(type); + } else { + klee_warning_once(allocSite, "Cannot determine memory alignment for " + "\"%s\". Using alignment of %zu.", + allocationSiteName.c_str(), forcedAlignment); + alignment = forcedAlignment; + } + } + + // Currently we require alignment be a power of 2 + if (!bits64::isPowerOfTwo(alignment)) { + klee_warning_once(allocSite, "Alignment of %zu requested for %s but this " + "not supported. Using alignment of %zu", + alignment, allocSite->getName().str().c_str(), + forcedAlignment); + alignment = forcedAlignment; + } + assert(bits64::isPowerOfTwo(alignment) && + "Returned alignment must be a power of two"); + return alignment; +} /// Interpreter *Interpreter::create(LLVMContext &ctx, const InterpreterOptions &opts, diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index 4970b8a0..7c18ae1f 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -507,6 +507,7 @@ public: std::map<const std::string*, std::set<unsigned> > &res); Expr::Width getWidthForLLVMType(LLVM_TYPE_Q llvm::Type *type) const; + size_t getAllocationAlignment(const llvm::Value *allocSite) const; }; } // End klee namespace diff --git a/lib/Core/MemoryManager.h b/lib/Core/MemoryManager.h index fc77b476..cc2073d8 100644 --- a/lib/Core/MemoryManager.h +++ b/lib/Core/MemoryManager.h @@ -40,7 +40,7 @@ public: * memory. */ MemoryObject *allocate(uint64_t size, bool isLocal, bool isGlobal, - const llvm::Value *allocSite, size_t alignment = 8); + const llvm::Value *allocSite, size_t alignment); MemoryObject *allocateFixed(uint64_t address, uint64_t size, const llvm::Value *allocSite); void deallocate(const MemoryObject *mo); diff --git a/test/regression/2016-12-14-alloc-alignment.c b/test/regression/2016-12-14-alloc-alignment.c new file mode 100644 index 00000000..db66d191 --- /dev/null +++ b/test/regression/2016-12-14-alloc-alignment.c @@ -0,0 +1,21 @@ +// RUN: %llvmgcc %s -Wall -emit-llvm -g -O0 -c -o %t.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --output-dir=%t.klee-out --exit-on-error %t.bc +#include <assert.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +// Global should be aligned on a 128-byte boundary +int foo __attribute__((aligned(128))); + +int main() { + int bar __attribute__((aligned(256))); + + // Check alignment of global + assert(((size_t)&foo) % 128 == 0); + + // Check alignment of local + assert(((size_t)&bar) % 256 == 0); + return 0; +} |