Using LLVM in a test suite run under LeakSanitizer

Hi,
I’m working on an out of tree llvm pass.

For unit testing, it is convenient to create llvm::Instruction*s manually, i.e. create an LLVMContext, IRBuilder, ScalarEvolution, etc, and then build a proxy instruction sequence I’m trying to analyze.

Unfortunately, this triggers the LeakSanitizer:

==30325==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 72 byte(s) in 3 object(s) allocated from:
    #0 0x7fc664abb1a8 in operator new(unsigned long) (/lib64/libasan.so.8+0xbb1a8)
    #1 0x7fc65ec18455 in llvm::StringMapEntry<llvm::Value*>* llvm::StringMapEntry<llvm::Value*>::Create<llvm::MallocAllocator>(llvm::StringRef, llvm::MallocAllocator&) /usr/src/debug/llvm-15.0.6-1.fc37.x86_64/lib/Support/MemAlloc.cpp:16
    #2 0x7ffef1971b4f  ([stack]+0x1ab4f)

Direct leak of 48 byte(s) in 2 object(s) allocated from:
    #0 0x7fc664abb1a8 in operator new(unsigned long) (/lib64/libasan.so.8+0xbb1a8)
    #1 0x7fc65ec18455 in llvm::StringMapEntry<llvm::Value*>* llvm::StringMapEntry<llvm::Value*>::Create<llvm::MallocAllocator>(llvm::StringRef, llvm::MallocAllocator&) /usr/src/debug/llvm-15.0.6-1.fc37.x86_64/lib/Support/MemAlloc.cpp:16
    #2 0x62580a in decltype(auto) llvm::dyn_cast<llvm::SCEVUnknown, llvm::SCEV const>(llvm::SCEV const*) /usr/include/llvm/Support/Casting.h:608

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x7fc664abb1a8 in operator new(unsigned long) (/lib64/libasan.so.8+0xbb1a8)
    #1 0x7fc65ec18455 in llvm::StringMapEntry<llvm::Value*>* llvm::StringMapEntry<llvm::Value*>::Create<llvm::MallocAllocator>(llvm::StringRef, llvm::MallocAllocator&) /usr/src/debug/llvm-15.0.6-1.fc37.x86_64/lib/Support/MemAlloc.cpp:16

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x7fc664abb1a8 in operator new(unsigned long) (/lib64/libasan.so.8+0xbb1a8)
    #1 0x7fc65ec18455 in llvm::StringMapEntry<llvm::Value*>* llvm::StringMapEntry<llvm::Value*>::Create<llvm::MallocAllocator>(llvm::StringRef, llvm::MallocAllocator&) /usr/src/debug/llvm-15.0.6-1.fc37.x86_64/lib/Support/MemAlloc.cpp:16
    #2 0x7ffef1971cbf  ([stack]+0x1acbf)

Indirect leak of 672 byte(s) in 7 object(s) allocated from:
    #0 0x7fc664abb1a8 in operator new(unsigned long) (/lib64/libasan.so.8+0xbb1a8)
    #1 0x7fc65ec16bb9 in llvm::User::operator new(unsigned long, unsigned int) (/lib64/libLLVM-15.so+0xe16bb9)

SUMMARY: AddressSanitizer: 840 byte(s) leaked in 14 allocation(s).

or

Indirect leak of 96 byte(s) in 1 object(s) allocated from:
    #0 0x7fe385ebb1a8 in operator new(unsigned long) (/lib64/libasan.so.8+0xbb1a8)
    #1 0x7fe37ffa1b39 in llvm::CastInst::Create(llvm::Instruction::CastOps, llvm::Value*, llvm::Type*, llvm::Twine const&, llvm::Instruction*) (/lib64/libLLVM-15.so+0xda1b39)
    #2 0x624f2d in llvm::IRBuilderBase::CreateUIToFP(llvm::Value*, llvm::Type*, llvm::Twine const&) /usr/include/llvm/IR/IRBuilder.h:1916
    #3 0x627247 in TestLoopFunction::CreateUIToF64(llvm::Value*) /home/chriselrod/Documents/progwork/cxx/LoopModels/test/./TestUtilities.hpp:133
    #4 0x56f2c4 in MeanStDevTest0_BasicAssertions_Test::TestBody() /home/chriselrod/Documents/progwork/cxx/LoopModels/test/dependence_test.cpp:962
    #5 0x8f8816 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:2599
    #6 0x8d6bbd in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:2635
    #7 0x83596f in testing::Test::Run() /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:2674
    #8 0x83929a in testing::TestInfo::Run() /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:2853
    #9 0x83d3d7 in testing::TestSuite::Run() /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:3012
    #10 0x8814df in testing::internal::UnitTestImpl::RunAllTests() /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:5870
    #11 0x8fd54e in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:2599
    #12 0x8dbc22 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:2635
    #13 0x875857 in testing::UnitTest::Run() /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest.cc:5444
    #14 0x7ea5ce in RUN_ALL_TESTS() /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/include/gtest/gtest.h:2293
    #15 0x7ea3fd in main /home/chriselrod/.cache/CPM/googletest/a36d6fcbd7356d396ea479e6b11f4b9760ad0c04/googletest/src/gtest_main.cc:51
    #16 0x7fe37e44a50f in __libc_start_call_main (/lib64/libc.so.6+0x2750f)

SUMMARY: AddressSanitizer: 305544 byte(s) leaked in 267 allocation(s).

(there were many more stack traces omitted above)

I don’t really see any documentation e.g. here on how to actually clean up the memory and avoid leaks.

Iterating over a set of llvm:Value*s and calling deleteValue() accesses invalid memory.
Perhaps deleteValue deletes some set of reachable values, and thus I need to call deleteValue() on only a few?
Create[InstructionName] and SCEVUnknown show up in a lot of the stacktraces (e.g. the above two examples), so I imagine I need to do something there.

I assume these leaks are because I’m not calling clean up functions that do get called?

Or maybe this is an xy problem, and there is a better way to set up running unit tests on LLVM IR?

Actually using opt plus a suppressions file…

> -----------------------------------------------------
> Suppressions used:
>   count      bytes template
>      26      48296 llvm::SmallVectorBase<unsigned int>::grow_pod
>       9       9216 llvm::DenseMap<llvm::BasicBlock*, unsigned int, llvm::DenseMapInfo<llvm::BasicBlock*, void>, llvm::detail::DenseMapPair<llvm::BasicBlock*, unsigned int> >::allocateBuckets(unsigned int)
>       9        440 std::__new_allocator<std::pair<llvm::BasicBlock*, Predicate::Set> >::allocate(unsigned long, void const*)
>       3        432 llvm::SmallVectorBase<unsigned int>::mallocForGrow(unsigned long, unsigned long, unsigned long&)
> -----------------------------------------------------

Seems there are a lot of leaks?