Alloc kind fixes
MODIFY
ir/attrs.cpp
ir/attrs.cpp
@@ -180,7 +180,7 @@ void ParamAttrs::merge(const ParamAttrs &other) {
static expr
encodePtrAttrs(State &s, const expr &ptrvalue, uint64_t derefBytes,
uint64_t derefOrNullBytes, uint64_t align, bool nonnull,
- bool nocapture, const expr &deref_expr) {
+ bool nocapture, const expr &deref_expr, Value *allocalign) {
auto &m = s.getMemory();
Pointer p(m, ptrvalue);
expr non_poison(true);
@@ -205,8 +205,14 @@ encodePtrAttrs(State &s, const expr &ptrvalue, uint64_t derefBytes,
} else if (align > 1)
non_poison &= Pointer(m, ptrvalue).isAligned(align);
- // TODO: handle alloc align
-
+ // TODO: handle non-constant allocalign
+ if (allocalign) {
+ StateValue align = s[*allocalign];
+ non_poison &= align.non_poison;
+ uint64_t val;
+ if (align.value.isUInt(val))
+ non_poison &= Pointer(m, ptrvalue).isAligned(val);
+ }
return non_poison;
}
@@ -214,7 +220,7 @@ StateValue ParamAttrs::encode(State &s, StateValue &&val, const Type &ty) const{
if (ty.isPtrType())
val.non_poison &=
encodePtrAttrs(s, val.value, getDerefBytes(), derefOrNullBytes, align,
- has(NonNull), has(NoCapture), {});
+ has(NonNull), has(NoCapture), {}, nullptr);
if (poisonImpliesUB()) {
s.addUB(std::move(val.non_poison));
@@ -301,7 +307,8 @@ bool FnAttrs::refinedBy(const FnAttrs &other) const {
}
StateValue FnAttrs::encode(State &s, StateValue &&val, const Type &ty,
- const expr &allocsize) const {
+ const expr &allocsize,
+ Value *allocalign) const {
if (has(FnAttrs::NNaN)) {
assert(ty.isFloatType());
val.non_poison &= !val.value.isNaN();
@@ -310,7 +317,7 @@ StateValue FnAttrs::encode(State &s, StateValue &&val, const Type &ty,
if (ty.isPtrType())
val.non_poison &=
encodePtrAttrs(s, val.value, derefBytes, derefOrNullBytes, align,
- has(NonNull), false, allocsize);
+ has(NonNull), false, allocsize, allocalign);
if (poisonImpliesUB()) {
s.addUB(std::move(val.non_poison));

MODIFY
ir/attrs.h
ir/attrs.h
@@ -96,7 +96,7 @@ public:
uint64_t derefBytes = 0; // Dereferenceable
uint64_t derefOrNullBytes = 0; // DereferenceableOrNull
- unsigned align = 0;
+ uint64_t align = 0;
unsigned allocsize_0;
unsigned allocsize_1 = -1u;
@@ -125,7 +125,8 @@ public:
// Encodes the semantics of attributes using UB and poison.
StateValue encode(State &s, StateValue &&val, const Type &ty,
- const smt::expr &allocsize) const;
+ const smt::expr &allocsize,
+ Value *allocalign) const;
friend std::ostream& operator<<(std::ostream &os, const FnAttrs &attr);
};

MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -1996,9 +1996,25 @@ pair<uint64_t, uint64_t> FnCall::getMaxAllocSize() const {
return { UINT64_MAX, getAlign() };
}
+static Value* get_align_arg(const vector<pair<Value*, ParamAttrs>> args) {
+ for (auto &[arg, attrs] : args) {
+ if (attrs.has(ParamAttrs::AllocAlign))
+ return arg;
+ }
+ return nullptr;
+}
+
+Value* FnCall::getAlignArg() const {
+ return get_align_arg(args);
+}
+
uint64_t FnCall::getAlign() const {
- // FIXME: needs to query allocalign param attr
- return attrs.align ? attrs.align : heap_block_alignment;
+ uint64_t align = 0;
+ // TODO: add support for non constant alignments
+ if (auto *arg = getAlignArg())
+ align = getIntOr(*arg, 0);
+
+ return max(align, attrs.align ? attrs.align : heap_block_alignment);
}
uint64_t FnCall::getMaxAccessSize() const {
@@ -2006,11 +2022,11 @@ uint64_t FnCall::getMaxAccessSize() const {
if (attrs.has(FnAttrs::DereferenceableOrNull))
sz = max(sz, attrs.derefOrNullBytes);
- for (auto &arg : args) {
- if (arg.second.has(ParamAttrs::Dereferenceable))
- sz = max(sz, arg.second.derefBytes);
- if (arg.second.has(ParamAttrs::DereferenceableOrNull))
- sz = max(sz, arg.second.derefOrNullBytes);
+ for (auto &[arg, attrs] : args) {
+ if (attrs.has(ParamAttrs::Dereferenceable))
+ sz = max(sz, attrs.derefBytes);
+ if (attrs.has(ParamAttrs::DereferenceableOrNull))
+ sz = max(sz, attrs.derefOrNullBytes);
}
return sz;
}
@@ -2208,7 +2224,7 @@ check_return_value(State &s, StateValue &&val, const Type &ty,
const vector<pair<Value*, ParamAttrs>> &args) {
auto [allocsize, np] = attrs.computeAllocSize(s, args);
s.addUB(std::move(np));
- return attrs.encode(s, std::move(val), ty, allocsize);
+ return attrs.encode(s, std::move(val), ty, allocsize, get_align_arg(args));
}
static StateValue
@@ -2343,7 +2359,8 @@ StateValue FnCall::toSMT(State &s) const {
false);
assert(getType().isPtrType());
- return attrs.encode(s, {std::move(ret), true}, getType(), size);
+ return attrs.encode(s, {std::move(ret), true}, getType(), size,
+ getAlignArg());
}
else if (attrs.has(AllocKind::Free)) {
auto &allocptr = s.getAndAddPoisonUB(get_alloc_ptr()).value;

MODIFY
ir/instr.h
ir/instr.h
@@ -898,6 +898,9 @@ private:
std::vector<std::pair<Value*, ParamAttrs>> args;
FnAttrs attrs;
bool approx = false;
+
+ Value* getAlignArg() const;
+
public:
FnCall(Type &type, std::string &&name, std::string &&fnName,
FnAttrs &&attrs = FnAttrs::None)

MODIFY
llvm_util/known_fns.cpp
llvm_util/known_fns.cpp
@@ -38,6 +38,10 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
}
};
+ auto set_align = [&](uint64_t align) {
+ attrs.align = max(attrs.align, align);
+ };
+
auto alloc_fns = [&](unsigned idx1, unsigned idx2 = -1u) {
ret_and_args_no_undef();
attrs.set(FnAttrs::InaccessibleMemOnly);
@@ -54,6 +58,9 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
};
switch (libfn) {
+ case llvm::LibFunc_valloc:
+ set_align(4096); // page size
+ [[fallthrough]];
case llvm::LibFunc_malloc:
alloc_fns(0);
attrs.set(FnAttrs::NoThrow);
@@ -73,12 +80,13 @@ static bool implict_attrs_(llvm::LibFunc libfn, FnAttrs &attrs,
RETURN_EXACT();
case llvm::LibFunc_realloc:
- alloc_fns(0);
+ alloc_fns(1);
attrs.set(FnAttrs::NoThrow);
attrs.allocfamily = "malloc";
attrs.add(AllocKind::Realloc);
attrs.add(AllocKind::Uninitialized);
set_param(0, ParamAttrs::AllocPtr);
+ set_param(0, ParamAttrs::NoCapture);
RETURN_EXACT();
case llvm::LibFunc_free:

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -1351,8 +1351,7 @@ public:
case llvm::Attribute::Alignment:
attrs.set(FnAttrs::Align);
- attrs.align = max(attrs.align,
- (unsigned)llvmattr.getAlignment()->value());
+ attrs.align = max(attrs.align, llvmattr.getAlignment()->value());
break;
default: break;
@@ -1433,6 +1432,23 @@ public:
attrs.allocsize_1 = *args.second;
break;
}
+ case llvm::Attribute::AllocKind: {
+ auto kind = llvmattr.getAllocKind();
+ if ((kind & llvm::AllocFnKind::Alloc) != llvm::AllocFnKind::Unknown)
+ attrs.add(AllocKind::Alloc);
+ if ((kind & llvm::AllocFnKind::Realloc) != llvm::AllocFnKind::Unknown)
+ attrs.add(AllocKind::Realloc);
+ if ((kind & llvm::AllocFnKind::Free) != llvm::AllocFnKind::Unknown)
+ attrs.add(AllocKind::Free);
+ if ((kind & llvm::AllocFnKind::Uninitialized)
+ != llvm::AllocFnKind::Unknown)
+ attrs.add(AllocKind::Uninitialized);
+ if ((kind & llvm::AllocFnKind::Zeroed) != llvm::AllocFnKind::Unknown)
+ attrs.add(AllocKind::Zeroed);
+ if ((kind & llvm::AllocFnKind::Aligned) != llvm::AllocFnKind::Unknown)
+ attrs.add(AllocKind::Aligned);
+ break;
+ }
case llvm::Attribute::NoReturn:
attrs.set(FnAttrs::NoReturn);
break;

Alloc kind fixes