Make malloc(poison) UB
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -2372,6 +2372,8 @@ void Malloc::print(std::ostream &os) const {
StateValue Malloc::toSMT(State &s) const {
auto &m = s.getMemory();
auto &[sz, np_size] = s.getAndAddUndefs(*size);
+ s.addUB(np_size);
+
unsigned align = heap_block_alignment;
expr nonnull = expr::mkBoolVar("malloc_never_fails");
auto [p_new, allocated]
@@ -2394,7 +2396,7 @@ StateValue Malloc::toSMT(State &s) const {
expr nullp = Pointer::mkNullPointer(m)();
m.free(expr::mkIf(sz == 0 || allocated, p, nullp), false);
}
- return { move(p_new), expr(np_size) };
+ return { move(p_new), true };
}
expr Malloc::getTypeConstraints(const Function &f) const {
@@ -2447,19 +2449,20 @@ void Calloc::print(std::ostream &os) const {
StateValue Calloc::toSMT(State &s) const {
auto &[nm, np_num] = s.getAndAddUndefs(*num);
auto &[sz, np_sz] = s.getAndAddUndefs(*size);
- auto np = np_num && np_sz;
+ s.addUB(np_num);
+ s.addUB(np_sz);
unsigned align = heap_block_alignment;
expr size = nm * sz;
expr nonnull = expr::mkBoolVar("malloc_never_fails");
auto [p, allocated] = s.getMemory().alloc(size, align, Memory::MALLOC,
- np && nm.mul_no_uoverflow(sz),
+ nm.mul_no_uoverflow(sz),
nonnull);
p = p.subst(allocated, true).simplify();
s.getMemory().memset(p, { expr::mkUInt(0, 8), true }, size, align, {}, false);
- return { move(p), move(np) };
+ return { move(p), true };
}
expr Calloc::getTypeConstraints(const Function &f) const {

ADD
tests/alive-tv/memory/malloc-noundef.srctgt.ll
+declare i8* @malloc(i64)
+declare void @f(i8*)
+
+define void @src(i64 %sz) {
+ %p = call i8* @malloc(i64 %sz)
+ %p.fr = freeze i8* %p
+ call void @f(i8* %p.fr)
+ ret void
+}
+
+define void @tgt(i64 %sz) {
+ %p = call i8* @malloc(i64 %sz)
+ call void @f(i8* %p)
+ ret void
+}

ADD
tests/alive-tv/memory/malloc-poison-ub.srctgt.ll
+declare i8* @malloc(i64)
+declare i8* @calloc(i64, i64)
+
+; Poison is a deferred UB, and the equivalent operation in C/C++ is immediate
+; UB. Therefore, it is safe to assume that malloc(poison) is UB in LLVM IR too.
+
+define void @src(i1 %cond) {
+ %poison = add nuw i64 -1, -1
+ br i1 %cond, label %MALLOC, label %CALLOC
+MALLOC:
+ call i8* @malloc(i64 %poison)
+ ret void
+CALLOC:
+ call i8* @calloc(i64 %poison, i64 %poison)
+ ret void
+}
+
+define void @tgt(i1 %cond) {
+ unreachable
+}

Make malloc(poison) UB (#469)