Issue 176669
Summary Using Fat LTO objects with Pass Plugin causes std::bad_alloc exception once a callback is registered
Labels new issue
Assignees
Reporter Sumandora
    In an attempt to write a transform pass for an entire project (opposed to a single translation unit).
I read in the docs, that this is apparently done by using Fat LTO objects to get the llvm bitcode back during linking.
I came up with the following setup:

<details>

<summary>
Boilerplate code
</summary>

a.cpp:
```cpp
int test(int x, int y) {
	return x + y;
}
```

b.cpp:
```cpp
#include <cstdio>

int test(int x, int y);

int main() { printf("%d\n", test(1, 2)); }
```
</details>

Then creating fat LTO objects

```sh
clang++ a.cpp -O3 -c -flto -ffat-lto-objects
clang++ b.cpp -O3 -c -flto -ffat-lto-objects
```

```cpp
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include <llvm/IR/Analysis.h>
#include <llvm/IR/PassManager.h>
#include <llvm/Pass.h>
#include <llvm/Passes/OptimizationLevel.h>

using namespace llvm;

llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
  return {
      LLVM_PLUGIN_API_VERSION, "HelloWorld", LLVM_VERSION_STRING,
 [](PassBuilder &PB) {
        static std::function<void(ModulePassManager &, OptimizationLevel)> F =
            [](ModulePassManager &Mgr, OptimizationLevel Level) {
            };
 PB.registerFullLinkTimeOptimizationEarlyEPCallback(F); // Removing this line fixes the crash

      }};
}

extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
  return getHelloWorldPluginInfo();
}

```

And then running

```sh
clang++ -Wl,-O3 -flto -fuse-ld=lld -ffat-lto-objects -Wl,--load-pass-plugin=/path/to/my/plugin/libHelloWorld.so a.o b.o
```
however this comes out as

```
libc++abi: terminating due to uncaught exception of type std::bad_alloc: std::bad_alloc
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /usr/lib/llvm/21/bin/ld.lld --hash-style=gnu --eh-frame-hdr -m elf_x86_64 -pie -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/lib/gcc/x86_64-pc-linux-gnu/15/../../../../lib64/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/15/../../../../lib64/crti.o /usr/lib/llvm/21/bin/../../../../lib/clang/21/lib/linux/clang_rt.crtbegin-x86_64.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/15 -L/usr/lib/gcc/x86_64-pc-linux-gnu/15/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/15/../../../../x86_64-pc-linux-gnu/lib -L/lib -L/usr/lib --fat-lto-objects -plugin-opt=mcpu=x86-64 -z relro -z now -O3 --load-pass-plugin=/tmp/llvm-tutor/build/libHelloWorld.so a.o b.o -lc++ -lm /usr/lib/llvm/21/bin/../../../../lib/clang/21/lib/linux/libclang_rt.builtins-x86_64.a --as-needed -lunwind --no-as-needed -lc /usr/lib/llvm/21/bin/../../../../lib/clang/21/lib/linux/libclang_rt.builtins-x86_64.a --as-needed -lunwind --no-as-needed /usr/lib/llvm/21/bin/../../../../lib/clang/21/lib/linux/clang_rt.crtend-x86_64.o /usr/lib/gcc/x86_64-pc-linux-gnu/15/../../../../lib64/crtn.o
 #0 0x00007fdbf43e78fa llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x41e78fa)
 #1 0x00007fdbf43e4bcb llvm::sys::RunSignalHandlers() (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x41e4bcb)
 #2 0x00007fdbf43e8514 (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x41e8514)
 #3 0x00007fdbeff68770 (/usr/lib64/libc.so.6+0x3d770)
 #4 0x00007fdbeffc14dc (/usr/lib64/libc.so.6+0x964dc)
 #5 0x00007fdbeff68636 raise (/usr/lib64/libc.so.6+0x3d636)
 #6 0x00007fdbeff4fe4b abort (/usr/lib64/libc.so.6+0x24e4b)
 #7 0x00007fdbf8524dc3 (/usr/lib64/libc++abi.so.1+0x36dc3)
 #8 0x00007fdbf850454f (/usr/lib64/libc++abi.so.1+0x1654f)
 #9 0x00007fdbf8523de7 (/usr/lib64/libc++abi.so.1+0x35de7)
#10 0x00007fdbf8526f96 (/usr/lib64/libc++abi.so.1+0x38f96)
#11 0x00007fdbf8526f74 (/usr/lib64/libc++abi.so.1+0x38f74)
#12 0x00007fdbf431b726 llvm::report_bad_alloc_error(char const*, bool) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x411b726)
#13 0x00007fdbf43659a2 llvm::SmallVectorBase<unsigned int>::mallocForGrow(void*, unsigned long, unsigned long, unsigned long&) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x41659a2)
#14 0x00007fdbefcea385 llvm::SmallVectorTemplateBase<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, false>::mallocForGrow(unsigned long, unsigned long&) /usr/lib/llvm/21/include/llvm/ADT/SmallVector.h:447:1
#15 0x00007fdbefcea1ba llvm::SmallVectorTemplateBase<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, false>::grow(unsigned long) /usr/lib/llvm/21/include/llvm/ADT/SmallVector.h:436:29
#16 0x00007fdbefcea053 std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)> const* llvm::SmallVectorTemplateCommon<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, void>::reserveForParamAndGetAddressImpl<llvm::SmallVectorTemplateBase<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, false>>(llvm::SmallVectorTemplateBase<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, false>*, std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)> const&, unsigned long) /usr/lib/llvm/21/include/llvm/ADT/SmallVector.h:245:30
#17 0x00007fdbefce9d95 llvm::SmallVectorTemplateBase<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, false>::reserveForParamAndGetAddress(std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)> const&, unsigned long) /usr/lib/llvm/21/include/llvm/ADT/SmallVector.h:380:3
#18 0x00007fdbefce9c2d llvm::SmallVectorTemplateBase<std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)>, false>::push_back(std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)> const&) /usr/lib/llvm/21/include/llvm/ADT/SmallVector.h:415:51
#19 0x00007fdbefce9b08 llvm::PassBuilder::registerFullLinkTimeOptimizationEarlyEPCallback(std::function<void (llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>&, llvm::OptimizationLevel)> const&) /usr/lib/llvm/21/include/llvm/Passes/PassBuilder.h:536:3
#20 0x00007fdbefce8dfe getHelloWorldPluginInfo()::'lambda'(llvm::PassBuilder&)::operator()(llvm::PassBuilder&) const /tmp/llvm-tutor/HelloWorld/HelloWorld.cpp:87:7
#21 0x00007fdbefce8e36 getHelloWorldPluginInfo()::'lambda'(llvm::PassBuilder&)::_FUN(llvm::PassBuilder&) /tmp/llvm-tutor/HelloWorld/HelloWorld.cpp:87:7
#22 0x00007fdbf5f739fc llvm::lto::opt(llvm::lto::Config const&, llvm::TargetMachine*, unsigned int, llvm::Module&, bool, llvm::ModuleSummaryIndex*, llvm::ModuleSummaryIndex const*, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>> const&) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x5d739fc)
#23 0x00007fdbf5f7565f llvm::lto::backend(llvm::lto::Config const&, std::__1::function<llvm::Expected<std::__1::unique_ptr<llvm::CachedFileStream, std::__1::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, unsigned int, llvm::Module&, llvm::ModuleSummaryIndex&) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x5d7565f)
#24 0x00007fdbf5f5b0a7 llvm::lto::LTO::runRegularLTO(std::__1::function<llvm::Expected<std::__1::unique_ptr<llvm::CachedFileStream, std::__1::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x5d5b0a7)
#25 0x00007fdbf5f5a2f0 llvm::lto::LTO::run(std::__1::function<llvm::Expected<std::__1::unique_ptr<llvm::CachedFileStream, std::__1::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache) (/usr/lib/llvm/21/bin/../lib64/libLLVM.so.21.1+libcxx+0x5d5a2f0)
#26 0x00007fdbf89e52c9 lld::elf::BitcodeCompiler::compile() (/usr/lib/llvm/21/bin/../lib64/liblldELF.so.21.1+libcxx+0x1e52c9)
#27 0x00007fdbf896c99c void lld::elf::LinkerDriver::compileBitcodeFiles<llvm::object::ELFType<(llvm::endianness)1, true>>(bool) (/usr/lib/llvm/21/bin/../lib64/liblldELF.so.21.1+libcxx+0x16c99c)
#28 0x00007fdbf894d3b1 void lld::elf::LinkerDriver::link<llvm::object::ELFType<(llvm::endianness)1, true>>(llvm::opt::InputArgList&) (/usr/lib/llvm/21/bin/../lib64/liblldELF.so.21.1+libcxx+0x14d3b1)
#29 0x00007fdbf8930cf1 lld::elf::LinkerDriver::linkerMain(llvm::ArrayRef<char const*>) (/usr/lib/llvm/21/bin/../lib64/liblldELF.so.21.1+libcxx+0x130cf1)
#30 0x00007fdbf892f7d9 lld::elf::link(llvm::ArrayRef<char const*>, llvm::raw_ostream&, llvm::raw_ostream&, bool, bool) (/usr/lib/llvm/21/bin/../lib64/liblldELF.so.21.1+libcxx+0x12f7d9)
#31 0x00007fdbf85768cc lld::unsafeLldMain(llvm::ArrayRef<char const*>, llvm::raw_ostream&, llvm::raw_ostream&, llvm::ArrayRef<lld::DriverDef>, bool) (/usr/lib/llvm/21/bin/../lib64/liblldCommon.so.21.1+libcxx+0x138cc)
#32 0x00005608593af194 lld_main(int, char**, llvm::ToolContext const&) (/usr/lib/llvm/21/bin/ld.lld+0x4194)
#33 0x00005608593afa58 main (/usr/lib/llvm/21/bin/ld.lld+0x4a58)
#34 0x00007fdbeff51f3b (/usr/lib64/libc.so.6+0x26f3b)
#35 0x00007fdbeff51feb __libc_start_main (/usr/lib64/libc.so.6+0x26feb)
#36 0x00005608593aee65 _start (/usr/lib/llvm/21/bin/ld.lld+0x3e65)
clang++: error: unable to execute command: Aborted
clang++: error: linker command failed due to signal (use -v to see invocation)
```

Removing `-ffat-lto-objects` from the linking step also solves this, but my pass builder callback will no longer run.

Analyzing this further, it seems like `PB` is corrupted once my function is run and thus interacting with the SmallVectors inside it, will obviously yield a crash. I have no clue why this happens and it feels very much like a fault on LLVMs end... I also sadly can't find any documentation on making a LTO plugin like I describe. There are LTO plugins, but they seem to not use fat LTO objects like I'm trying to. Some help is very appreciated, thanks in advance.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to