add support for non-null malloc (fixes
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -2972,11 +2972,10 @@ StateValue Malloc::toSMT(State &s) const {
if (!ptr) {
if (isNonNull) {
- // TODO: In C++ we need to throw an exception if the allocation fails,
- // but exception hasn't been modeled yet
s.addPre(move(allocated));
ret = p_new;
}
+ // TODO: In C++ we need to throw an exception if the allocation fails.
} else {
auto &[p, np_ptr] = s.getAndAddUndefs(*ptr);
s.addUB(np_ptr);
@@ -3003,9 +3002,11 @@ expr Malloc::getTypeConstraints(const Function &f) const {
}
unique_ptr<Instr> Malloc::dup(const string &suffix) const {
- if (ptr)
- return make_unique<Malloc>(getType(), getName() + suffix, *ptr, *size);
- return make_unique<Malloc>(getType(), getName() + suffix, *size, isNonNull);
+ return ptr
+ ? make_unique<Malloc>(getType(), getName() + suffix, *ptr, *size, isNonNull,
+ align)
+ : make_unique<Malloc>(getType(), getName() + suffix, *size, isNonNull,
+ align);
}

MODIFY
ir/instr.h
ir/instr.h
@@ -608,19 +608,18 @@ public:
class Malloc final : public MemInstr {
Value *ptr = nullptr, *size;
uint64_t align;
- // Is this malloc (or equivalent operation, like new()) never returning
- // null?
bool isNonNull = false;
public:
Malloc(Type &type, std::string &&name, Value &size, bool isNonNull,
- uint64_t align = 0)
+ uint64_t align)
: MemInstr(type, std::move(name)), size(&size), align(align),
isNonNull(isNonNull) {}
Malloc(Type &type, std::string &&name, Value &ptr, Value &size,
- uint64_t align = 0)
- : MemInstr(type, std::move(name)), ptr(&ptr), size(&size), align(align) {}
+ bool isNonNull, uint64_t align)
+ : MemInstr(type, std::move(name)), ptr(&ptr), size(&size), align(align),
+ isNonNull(isNonNull) {}
Value& getSize() const { return *size; }
uint64_t getAlign() const;

MODIFY
llvm_util/known_fns.cpp
llvm_util/known_fns.cpp
@@ -39,11 +39,14 @@ known_call(llvm::CallInst &i, const llvm::TargetLibraryInfo &TLI,
// TODO: add support for checking mismatch of C vs C++ alloc fns
if (llvm::isMallocOrCallocLikeFn(&i, &TLI)) {
+ bool isNonNull = i.hasRetAttr(llvm::Attribute::NonNull);
+ //TODO: also null for C++'s new throwing operator
+
// aligned malloc
if (auto *algn = llvm::getAllocAlignment(&i, &TLI)) {
if (auto algnint = dyn_cast<llvm::ConstantInt>(algn)) {
RETURN_VAL(
- make_unique<Malloc>(*ty, value_name(i), *args[1], false,
+ make_unique<Malloc>(*ty, value_name(i), *args[1], isNonNull,
algnint->getZExtValue()));
} else {
// TODO: add support for non-const alignments
@@ -58,13 +61,13 @@ known_call(llvm::CallInst &i, const llvm::TargetLibraryInfo &TLI,
make_unique<Calloc>(*ty, value_name(i), *args[0], *args[1], align(i)));
// malloc or new
- bool isNonNull = i.getCalledFunction()->getName() != "malloc";
RETURN_VAL(
make_unique<Malloc>(*ty, value_name(i), *args[0], isNonNull, align(i)));
}
if (llvm::isReallocLikeFn(&i, &TLI)) {
- RETURN_VAL(
- make_unique<Malloc>(*ty, value_name(i), *args[0], *args[1], align(i)));
+ bool isNonNull = i.hasRetAttr(llvm::Attribute::NonNull);
+ RETURN_VAL(make_unique<Malloc>(*ty, value_name(i), *args[0], *args[1],
+ isNonNull, align(i)));
}
if (llvm::isFreeCall(&i, &TLI)) {
if (i.hasFnAttr(llvm::Attribute::NoFree)) {

ADD
tests/alive-tv/memory/malloc-nonnull.srctgt.ll
+define i1 @src() {
+ %m = call nonnull i8* @malloc(i64 4)
+ %n = call nonnull i8* @malloc(i64 4)
+ call void @unknown(i8* %n)
+ %cmp = icmp eq i8* %m, %n
+ ret i1 %cmp
+}
+
+define i1 @tgt() {
+ %n = call nonnull i8* @malloc(i64 4)
+ call void @unknown(i8* %n)
+ ret i1 false
+}
+
+declare i8* @malloc(i64)
+declare void @unknown(i8*)

MODIFY
tools/alive_parser.cpp
tools/alive_parser.cpp
@@ -1099,7 +1099,7 @@ static unique_ptr<Instr> parse_malloc(string_view name) {
auto &op = parse_operand(ty);
// Malloc returns a pointer at address space 0
Type &pointer_type = get_pointer_type(0);
- return make_unique<Malloc>(pointer_type, string(name), op, false);
+ return make_unique<Malloc>(pointer_type, string(name), op, false, 0);
}
static unique_ptr<Instr> parse_extractelement(string_view name) {

add support for non-null malloc (fixes #776)