fix missing overflow check of malloc sz
MODIFY
ir/attrs.cpp
ir/attrs.cpp
@@ -231,6 +231,12 @@ FnAttrs::computeAllocSize(State &s,
expr allocsize = arg0.value.zextOrTrunc(bits_size_t);
expr np_size = arg0.non_poison;
+ auto check_trunc = [&](const expr &var) {
+ if (var.bits() > bits_size_t)
+ np_size &= var.extract(var.bits()-1, bits_size_t) == 0;
+ };
+ check_trunc(arg0.value);
+
if (allocsize_1 != -1u) {
auto &arg1 = s[*args[allocsize_1].first];
s.addUB(arg1.non_poison);
@@ -239,6 +245,7 @@ FnAttrs::computeAllocSize(State &s,
np_size &= arg1.non_poison;
np_size &= allocsize.mul_no_uoverflow(v);
allocsize = allocsize * v;
+ check_trunc(arg1.value);
}
return { std::move(allocsize), std::move(np_size) };
}

MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -1996,10 +1996,6 @@ pair<uint64_t, uint64_t> FnCall::getMaxAllocSize() const {
return { UINT64_MAX, getAlign() };
}
-bool FnCall::canFree() const {
- return !hasAttribute(FnAttrs::NoFree);
-}
-
uint64_t FnCall::getAlign() const {
// FIXME: needs to query allocalign param attr
return attrs.align ? attrs.align : heap_block_alignment;
@@ -3142,7 +3138,6 @@ MemInstr::ByteAccessInfo MemInstr::ByteAccessInfo::full(unsigned byteSize) {
DEFINE_AS_RETZERO(Alloc, getMaxAccessSize);
DEFINE_AS_RETZERO(Alloc, getMaxGEPOffset);
DEFINE_AS_EMPTYACCESS(Alloc);
-DEFINE_AS_RETFALSE(Alloc, canFree);
pair<uint64_t, uint64_t> Alloc::getMaxAllocSize() const {
if (auto bytes = getInt(*size)) {
@@ -3218,7 +3213,6 @@ DEFINE_AS_RETZEROALIGN(StartLifetime, getMaxAllocSize);
DEFINE_AS_RETZERO(StartLifetime, getMaxAccessSize);
DEFINE_AS_RETZERO(StartLifetime, getMaxGEPOffset);
DEFINE_AS_EMPTYACCESS(StartLifetime);
-DEFINE_AS_RETFALSE(StartLifetime, canFree);
vector<Value*> StartLifetime::operands() const {
return { ptr };
@@ -3256,10 +3250,6 @@ vector<Value*> EndLifetime::operands() const {
return { ptr };
}
-bool EndLifetime::canFree() const {
- return true;
-}
-
void EndLifetime::rauw(const Value &what, Value &with) {
RAUW(ptr);
}
@@ -3290,7 +3280,6 @@ void GEP::addIdx(uint64_t obj_size, Value &idx) {
DEFINE_AS_RETZEROALIGN(GEP, getMaxAllocSize);
DEFINE_AS_RETZERO(GEP, getMaxAccessSize);
DEFINE_AS_EMPTYACCESS(GEP);
-DEFINE_AS_RETFALSE(GEP, canFree);
static unsigned off_used_bits(const Value &v) {
if (auto c = isCast(ConversionOp::SExt, v))
@@ -3432,7 +3421,6 @@ unique_ptr<Instr> GEP::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(Load, getMaxAllocSize);
DEFINE_AS_RETZERO(Load, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(Load, canFree);
uint64_t Load::getMaxAccessSize() const {
return Memory::getStoreByteSize(getType());
@@ -3475,7 +3463,6 @@ unique_ptr<Instr> Load::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(Store, getMaxAllocSize);
DEFINE_AS_RETZERO(Store, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(Store, canFree);
uint64_t Store::getMaxAccessSize() const {
return Memory::getStoreByteSize(val->getType());
@@ -3525,7 +3512,6 @@ unique_ptr<Instr> Store::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(Memset, getMaxAllocSize);
DEFINE_AS_RETZERO(Memset, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(Memset, canFree);
uint64_t Memset::getMaxAccessSize() const {
return getIntOr(*bytes, UINT64_MAX);
@@ -3587,7 +3573,6 @@ unique_ptr<Instr> Memset::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(FillPoison, getMaxAllocSize);
DEFINE_AS_RETZERO(FillPoison, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(FillPoison, canFree);
uint64_t FillPoison::getMaxAccessSize() const {
return getGlobalVarSize(ptr);
@@ -3627,7 +3612,6 @@ unique_ptr<Instr> FillPoison::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(Memcpy, getMaxAllocSize);
DEFINE_AS_RETZERO(Memcpy, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(Memcpy, canFree);
uint64_t Memcpy::getMaxAccessSize() const {
return getIntOr(*bytes, UINT64_MAX);
@@ -3704,7 +3688,6 @@ unique_ptr<Instr> Memcpy::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(Memcmp, getMaxAllocSize);
DEFINE_AS_RETZERO(Memcmp, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(Memcmp, canFree);
uint64_t Memcmp::getMaxAccessSize() const {
return getIntOr(*num, UINT64_MAX);
@@ -3819,7 +3802,6 @@ unique_ptr<Instr> Memcmp::dup(Function &f, const string &suffix) const {
DEFINE_AS_RETZEROALIGN(Strlen, getMaxAllocSize);
DEFINE_AS_RETZERO(Strlen, getMaxGEPOffset);
-DEFINE_AS_RETFALSE(Strlen, canFree);
uint64_t Strlen::getMaxAccessSize() const {
return getGlobalVarSize(ptr);

MODIFY
ir/instr.h
ir/instr.h
@@ -597,9 +597,6 @@ public:
// already contains the offset.
virtual uint64_t getMaxGEPOffset() const = 0;
- // Can this instruction free allocated objects?
- virtual bool canFree() const = 0;
-
struct ByteAccessInfo {
bool hasIntByteAccess = false;
bool doesPtrLoad = false;
@@ -639,7 +636,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -661,7 +657,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -682,7 +677,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -711,7 +705,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -737,7 +730,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -765,7 +757,6 @@ public:
uint64_t getMaxAccessSize() const override;
uint64_t getMaxAccessStride() const;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -792,7 +783,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -813,7 +803,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -843,7 +832,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -869,7 +857,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -893,7 +880,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;
@@ -928,7 +914,6 @@ public:
std::pair<uint64_t, uint64_t> getMaxAllocSize() const override;
uint64_t getMaxAccessSize() const override;
uint64_t getMaxGEPOffset() const override;
- bool canFree() const override;
ByteAccessInfo getByteAccessInfo() const override;
std::vector<Value*> operands() const override;

MODIFY
llvm_util/known_fns.cpp
llvm_util/known_fns.cpp
@@ -42,7 +42,6 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
ret_and_args_no_undef();
attrs.set(FnAttrs::InaccessibleMemOnly);
attrs.set(FnAttrs::NoAlias);
- attrs.set(FnAttrs::NoThrow);
attrs.set(FnAttrs::WillReturn);
attrs.set(FnAttrs::AllocSize);
attrs.allocsize_0 = idx1;
@@ -57,6 +56,7 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
switch (libfn) {
case llvm::LibFunc_malloc:
alloc_fns(0);
+ attrs.set(FnAttrs::NoThrow);
attrs.set(FnAttrs::NoFree);
attrs.allocfamily = "malloc";
attrs.add(AllocKind::Alloc);
@@ -65,6 +65,7 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
case llvm::LibFunc_calloc:
alloc_fns(0, 1);
+ attrs.set(FnAttrs::NoThrow);
attrs.set(FnAttrs::NoFree);
attrs.allocfamily = "malloc";
attrs.add(AllocKind::Alloc);
@@ -73,6 +74,7 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
case llvm::LibFunc_realloc:
alloc_fns(0);
+ attrs.set(FnAttrs::NoThrow);
attrs.allocfamily = "malloc";
attrs.add(AllocKind::Realloc);
attrs.add(AllocKind::Uninitialized);

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -1521,6 +1521,8 @@ public:
// merge param attrs computed above
unsigned idx = 0;
for (auto *in : args) {
+ if (idx == param_attrs.size())
+ break;
static_cast<Input*>(in)->merge(param_attrs[idx++]);
}
}

fix missing overflow check of malloc sz