diff --git a/ir/attrs.h b/ir/attrs.h index 9ba88e959..9457b66b3 100644 --- a/ir/attrs.h +++ b/ir/attrs.h @@ -159,6 +159,7 @@ class FnAttrs final { void add(AllocKind k) { allockind |= (uint8_t)k; } bool has(AllocKind k) const { return allockind & (uint8_t)k; } bool isAlloc() const { return allockind != 0 || has(AllocSize); } + bool isAllocWithoutSize() const { return allockind != 0 && !has(AllocSize); } void inferImpliedAttributes(); diff --git a/ir/instr.cpp b/ir/instr.cpp index 3a560a57d..472c5174e 100644 --- a/ir/instr.cpp +++ b/ir/instr.cpp @@ -2768,7 +2768,31 @@ StateValue FnCall::toSMT(State &s) const { if (attrs.has(AllocKind::Alloc) || attrs.has(AllocKind::Realloc) || attrs.has(FnAttrs::AllocSize)) { - auto [size, np_size] = attrs.computeAllocSize(s, args); + + smt::expr size; + smt::expr np_size; + + if (!attrs.has(FnAttrs::AllocSize)) { + static IntType sizet_type(string("size_t"), config::max_sizet_bits); + FnAttrs new_attrs = attrs; + new_attrs.mem.setCanOnlyAccess(MemoryAccess::Inaccessible); + auto result = s.addFnCall(std::move(fnName_mangled).str(), std::move(inputs), + std::move(ptr_inputs), sizet_type, StateValue{}, + nullptr, std::vector{}, new_attrs, indirect_hash); + size = std::move(result.value); + np_size = std::move(result.non_poison); + } else { + + FnAttrs new_attrs = attrs; + new_attrs.mem.setCanOnlyAccess(MemoryAccess::Inaccessible); + s.addFnCall(std::move(fnName_mangled).str(), std::move(inputs), + std::move(ptr_inputs), Type::voidTy, StateValue{}, + nullptr, std::vector{}, new_attrs, indirect_hash); + auto result = attrs.computeAllocSize(s, args); + size = std::move(result.first); + np_size = std::move(result.second); + } + expr nonnull = attrs.isNonNull() ? expr(true) : expr::mkBoolVar("malloc_never_fails"); // FIXME: alloc-family below diff --git a/tests/alive-tv/attrs/noallocsize-fn.srctgt.ll b/tests/alive-tv/attrs/noallocsize-fn.srctgt.ll new file mode 100644 index 000000000..967a4f32c --- /dev/null +++ b/tests/alive-tv/attrs/noallocsize-fn.srctgt.ll @@ -0,0 +1,14 @@ +; ERROR: Source and target don't have the same return domain + +define i64 @src() { + %stack = call ptr @myalloc() + %sz = call i64 @llvm.objectsize.i64.p0(ptr %stack, i1 false, i1 false, i1 false) + ret i64 %sz +} + +define i64 @tgt() { + ret i64 -1 +} + +declare ptr @myalloc() allockind("alloc") +declare i64 @llvm.objectsize.i64.p0(ptr, i1, i1, i1) diff --git a/tools/transform.cpp b/tools/transform.cpp index 8f705526d..b6f63cfb2 100644 --- a/tools/transform.cpp +++ b/tools/transform.cpp @@ -1162,6 +1162,9 @@ static void calculateAndInitConstants(Transform &t) { fn->getGlobalVar(string_view(call->getFnName()).substr(1)) && inaccessiblememonly_fns.emplace(call->getName()).second) ++num_inaccessiblememonly_fns; + } else { + if (inaccessiblememonly_fns.emplace(call->getName()).second) + ++num_inaccessiblememonly_fns; } if (call->isIndirect()) { has_indirect_fncalls = true;