diff --git a/svf-llvm/lib/LLVMUtil.cpp b/svf-llvm/lib/LLVMUtil.cpp index d063d2b8bb..c33b5ab508 100644 --- a/svf-llvm/lib/LLVMUtil.cpp +++ b/svf-llvm/lib/LLVMUtil.cpp @@ -1268,6 +1268,234 @@ s64_t LLVMUtil::getCaseValue(const SwitchInst &switchInst, SuccBBAndCondValPair namespace SVF { + + +/** + * Determines whether the memory allocation size associated with this AddrStmt is constant. + * + * @return True if the allocation size is constant, false otherwise. + */ +bool AddrStmt::isConstantAllocSize() const { + // Retrieve the LLVM Value associated with this AddrStmt from the LLVMModuleSet. + const llvm::Value* value = LLVMModuleSet::getLLVMModuleSet()->getLLVMValue(this->getLHSVar()->getValue()); + + // Assert failure if there's no associated LLVM Value. + if (!value) { + assert(false && "this AddrStmt has no LLVM Value"); + } + + // Handle the case where the value is an AllocaInst (stack allocation). + if (const llvm::AllocaInst* allocaInst = llvm::dyn_cast(value)) { + const llvm::Value* sizeOperand = allocaInst->getArraySize(); + // Check if the size of the allocation is a constant integer. + return llvm::isa(sizeOperand); + } + // Handle the case where the value is a GlobalVariable. + else if (const llvm::GlobalVariable* globalVar = llvm::dyn_cast(value)) { + // Check if the GlobalVariable is constant. + return globalVar->isConstant(); + } + // Handle the case where the value is a CallInst (dynamic memory allocation). + else if (const llvm::CallInst* callInst = llvm::dyn_cast(value)) { + if (const llvm::Function* calledFunction = callInst->getCalledFunction()) { + std::string functionName = calledFunction->getName().str(); + + // Check if the function called is 'malloc'. + if (functionName == "malloc") { + if (callInst->getNumOperands() > 0) { + const llvm::Value* arg = callInst->getArgOperand(0); + // Check if the argument to malloc is a constant integer. + return llvm::isa(arg); + } + } + // Check if the function called is 'calloc'. + else if (functionName == "calloc") { + if (callInst->getNumOperands() > 1) { + const llvm::Value* arg1 = callInst->getArgOperand(0); + const llvm::Value* arg2 = callInst->getArgOperand(1); + // Check if both arguments to calloc are constant integers. + return llvm::isa(arg1) && llvm::isa(arg2); + } + } + // Handle other similar functions for memory allocation. + else { + if (callInst->getNumOperands() > 0) { + const llvm::Value* arg = callInst->getArgOperand(0); + // Check if the first argument is a constant integer. + return llvm::isa(arg); + } + // Assert failure if the allocation function does not have any arguments. + assert(false && "alloc function has no arg"); + } + } + // Assert failure if there's no function called in this AddrStmt. + else { + assert(false && "this AddrStmt has no called Function"); + } + } + // Handle the case where the instruction is unknown and not an allocation/malloc/global variable. + else { + assert(false && "unknown inst, it is not Alloc/Malloc/GlobalValue"); + } + + return false; +} + + +/** + * Retrieves the constant byte size of the memory allocation associated with this AddrStmt. + * + * @return The byte size of the memory allocation if it is constant. + * Throws an assertion if the size is not constant or the LLVM value is not recognized. + */ +u32_t AddrStmt::getConstLLVMByteSize() const { + // Retrieve the LLVM Value associated with this AddrStmt. + const llvm::Value* value = LLVMModuleSet::getLLVMModuleSet()->getLLVMValue(this->getLHSVar()->getValue()); + + // Assert failure if there's no associated LLVM Value. + if (!value) { + assert(false && "this AddrStmt has no LLVM Value"); + } + + // Handle the case where the value is an AllocaInst (stack allocation). + if (const llvm::AllocaInst* allocaInst = llvm::dyn_cast(value)) { + // Check if the size of the allocation is a constant integer. + if (const llvm::ConstantInt* constSizeVal = llvm::dyn_cast(allocaInst->getArraySize())) { + // Retrieve the number of elements to be allocated. + uint64_t numElements = constSizeVal->getZExtValue(); + + // Retrieve the type being allocated and calculate its size. + llvm::Type* allocatedType = allocaInst->getAllocatedType(); + const llvm::DataLayout& dataLayout = allocaInst->getModule()->getDataLayout(); + uint64_t elementSize = dataLayout.getTypeAllocSize(allocatedType); + + // Calculate and return the total size of the allocation. + return numElements * elementSize; + } + } + // Handle the case where the value is a GlobalVariable. + else if (const llvm::GlobalVariable* globalVar = llvm::dyn_cast(value)) { + // If the global variable has an initializer, calculate its size. + if (globalVar->hasInitializer()) { + llvm::Type* type = globalVar->getValueType(); + const llvm::DataLayout& dataLayout = globalVar->getParent()->getDataLayout(); + return dataLayout.getTypeAllocSize(type); + } + } + // Handle the case where the value is a CallInst (dynamic memory allocation). + else if (const llvm::CallInst* callInst = llvm::dyn_cast(value)) { + if (const llvm::Function* calledFunction = callInst->getCalledFunction()) { + std::string functionName = calledFunction->getName().str(); + + // Check if the function called is 'malloc' and process its argument. + if (functionName == "malloc" && callInst->getNumOperands() > 0) { + if (const llvm::ConstantInt* arg = llvm::dyn_cast(callInst->getArgOperand(0))) { + return arg->getZExtValue(); + } + } + // Check if the function called is 'calloc' and process its arguments. + else if (functionName == "calloc" && callInst->getNumOperands() > 1) { + if (const llvm::ConstantInt* arg1 = llvm::dyn_cast(callInst->getArgOperand(0))) { + if (const llvm::ConstantInt* arg2 = llvm::dyn_cast(callInst->getArgOperand(1))) { + return arg1->getZExtValue() * arg2->getZExtValue(); + } + } + } + // Handle other similar functions for memory allocation. + else { + if (callInst->getNumOperands() > 0) { + if(const llvm::ConstantInt* arg = llvm::dyn_cast(callInst->getArgOperand(0))){ + return arg->getZExtValue(); + } + } + } + } + } + // Assert failure if the allocation size is unknown or the instance is not a recognized type. + assert(false && "unknown alloc size (you should check isConstantAllocSize() first), or unknown inst"); +} + + +/** + * Retrieves the runtime byte size of the memory allocation associated with this AddrStmt. + * + * @return An SVFAllocationInfo object containing the size(s) of the memory allocation and the element size. + * Throws an assertion if the LLVM value is not recognized or the size cannot be determined. + */ +SVFAllocationInfo AddrStmt::getRuntimeLLVMByteSize() const { + // Retrieve the LLVM Value associated with this AddrStmt. + const llvm::Value* value = LLVMModuleSet::getLLVMModuleSet()->getLLVMValue(this->getLHSVar()->getValue()); + + // Assert failure if there's no associated LLVM Value. + if (!value) { + assert(false && "this AddrStmt has no LLVM Value"); + } + + // Vector to store the size(s) of the allocation. + std::vector sizes; + + // Default element size is set to 1. + u32_t elementSize = 1; + + // Handle the case where the value is an AllocaInst (stack allocation). + if (const llvm::AllocaInst* allocaInst = llvm::dyn_cast(value)) { + // Add the array size to the sizes vector. + sizes.push_back(allocaInst->getArraySize()); + + // Retrieve the type being allocated and calculate its size. + llvm::Type* allocatedType = allocaInst->getAllocatedType(); + const llvm::DataLayout& dataLayout = allocaInst->getModule()->getDataLayout(); + elementSize = dataLayout.getTypeAllocSize(allocatedType); + } + // Handle the case where the value is a GlobalVariable. + else if (const llvm::GlobalVariable* globalVar = llvm::dyn_cast(value)) { + // Global variables usually have constant sizes, assert failure. + assert (false && "usually the size of global value is const"); + } + // Handle the case where the value is a CallInst (dynamic memory allocation). + else if (const llvm::CallInst* callInst = llvm::dyn_cast(value)) { + if (const llvm::Function* calledFunction = callInst->getCalledFunction()) { + std::string functionName = calledFunction->getName().str(); + + // Check if the function called is 'malloc' and process its argument. + if (functionName == "malloc") { + if (callInst->getNumOperands() > 0) { + sizes.push_back(callInst->getArgOperand(0)); + } + } + // Check if the function called is 'calloc' and process its arguments. + else if (functionName == "calloc") { + if (callInst->getNumOperands() > 1) { + sizes.push_back(callInst->getArgOperand(0)); + sizes.push_back(callInst->getArgOperand(1)); + } + } + // Handle other similar functions for memory allocation. + else { + if (callInst->getNumOperands() > 0) { + sizes.push_back(callInst->getArgOperand(0)); + } + } + } + } + + // Assert failure if the allocation instruction is unknown. + assert(sizes.size() > 0 && "unknown alloc inst"); + + // Vector to store the SVFValues corresponding to the LLVM Values. + std::vector svfSizes; + // Transform LLVM Values to SVFValues. + std::transform(sizes.begin(), sizes.end(), svfSizes.begin(), + [](const llvm::Value* value) -> const SVFValue* { + return LLVMModuleSet::getLLVMModuleSet()->getSVFValue(value); + } + ); + + // Return the allocation information. + return SVFAllocationInfo(svfSizes, elementSize); +} + + // getLLVMByteSize u32_t SVFType::getLLVMByteSize() const { diff --git a/svf/include/SVFIR/SVFStatements.h b/svf/include/SVFIR/SVFStatements.h index 39c1c4d017..885dfe7fd0 100644 --- a/svf/include/SVFIR/SVFStatements.h +++ b/svf/include/SVFIR/SVFStatements.h @@ -342,6 +342,15 @@ class AddrStmt: public AssignStmt AddrStmt(SVFVar* s, SVFVar* d) : AssignStmt(s, d, SVFStmt::Addr) {} virtual const std::string toString() const override; + + /// Determines whether the memory allocation size associated with this AddrStmt is constant. + bool isConstantAllocSize() const; + + /// Retrieves the constant byte size of the memory allocation associated with this AddrStmt. + u32_t getConstLLVMByteSize() const; + + /// Retrieves the runtime byte size of the memory allocation associated with this AddrStmt. + SVFAllocationInfo getRuntimeLLVMByteSize() const; }; /*! diff --git a/svf/include/SVFIR/SVFValue.h b/svf/include/SVFIR/SVFValue.h index f300c4c6d9..3520509eec 100644 --- a/svf/include/SVFIR/SVFValue.h +++ b/svf/include/SVFIR/SVFValue.h @@ -1098,6 +1098,17 @@ class SVFMetadataAsValue : public SVFOtherValue } }; +/* + * This class is only for AddrStmt's runtime allocated bytes + */ +struct SVFAllocationInfo { + std::vector sizes; + u32_t elementSize; + + SVFAllocationInfo(std::vector sizes, u32_t elementSize) + : sizes(std::move(sizes)), elementSize(elementSize) {} +}; + class CallSite { diff --git a/svf/include/Util/Options.h b/svf/include/Util/Options.h index d52a1793da..c8f9de5f5c 100644 --- a/svf/include/Util/Options.h +++ b/svf/include/Util/Options.h @@ -37,6 +37,9 @@ class Options /// Maximum number of field derivations for an object. static const Option MaxFieldLimit; + /// Maximum number of byte offset for an object + static const Option MaxByteLimit; + /// Whether to stage Andersen's with Steensgaard and cluster based on that data. static const Option ClusterAnder; diff --git a/svf/lib/SVFIR/SVFStatements.cpp b/svf/lib/SVFIR/SVFStatements.cpp index 5335bc27a7..82990ae26e 100644 --- a/svf/lib/SVFIR/SVFStatements.cpp +++ b/svf/lib/SVFIR/SVFStatements.cpp @@ -71,6 +71,24 @@ const std::string SVFStmt::toString() const return rawstr.str(); } +__attribute__((weak)) +bool AddrStmt::isConstantAllocSize() const { + assert("AddrStmt::isConstantAllocSize should be implemented or supported by fronted" && false); + abort(); +} + +__attribute__((weak)) +u32_t AddrStmt::getConstLLVMByteSize() const { + assert("AddrStmt::getConstLLVMByteSize should be implemented or supported by fronted" && false); + abort(); +} + +__attribute__((weak)) +SVFAllocationInfo AddrStmt::getRuntimeLLVMByteSize() const { + assert("AddrStmt::getRuntimeLLVMByteSize should be implemented or supported by fronted" && false); + abort(); +} + const std::string AddrStmt::toString() const { std::string str; diff --git a/svf/lib/Util/Options.cpp b/svf/lib/Util/Options.cpp index 918b66d297..36659c1212 100644 --- a/svf/lib/Util/Options.cpp +++ b/svf/lib/Util/Options.cpp @@ -40,6 +40,12 @@ const Option Options::MaxFieldLimit( 512 ); +const Option Options::MaxByteLimit( + "byte-limit", + "Maximum number of byte offset for field sensitive analysis", + 99999 +); + const OptionMap Options::ptDataBacking( "ptd", "Overarching points-to data structure",