Hi there, hackers! I ran into a JIT crash on openSUSE Leap 15.6 (LLVM 17.0.6, clang 17.0.6, GCC 13, just default devel packages). With jit_above_cost and jit_inline_above_cost both 0, check-world loses about a hundred tests to signal 11, always starting in the same place: ``` LOG: executing LLVM IR with JIT server closed the connection unexpectedly ... LOG: server process (PID ...) was terminated by signal 11: Segmentation Fault DETAIL: Failed process was running: SELECT t1.b1, NOT t1.b1, t2.b1, NOT t2.b1 FROM BOOLTBL1 t1, BOOLTBL2 t2; ```
If I skip llvm_inline(), everything is green. Ubuntu with LLVM 18 is fine too.
So this is inlining, and it is specific to that toolchain.
I spent a while looking at bitcode loading and IRMover before a backtrace made
it obvious that it dies inside llvm::MemoryBuffer::getFile(), called from
llvm_load_summary() on postgres.index.bc, before the file is even opened.
```
#0 llvm::MemoryBuffer::getFile(...)
#1 llvm_load_summary
#2 add_module_to_inline_search_path
#3 llvm_build_inline_plan
#4 llvm_inline
```
load_module() already reads the per-object .bc files through
LLVMCreateMemoryBufferWithContentsOfFile() and never crashes. A tiny C++
program that just calls getFile("/etc/hostname") SIGSEGVs the same way; the C
API on that path, and on the 2.4MB index, is fine, and getModuleSummaryIndex()
then works. After switching llvm_load_summary() to the C API, the boolean join
comes back with 4 rows and inlining actually happens:
```
DEBUG: time to inline: 21.186 ms, successfully inlined 6 functions
```
Andres, Thomas: I am copying you because you're knowing about this part more
than anyone, and some already looked at this symbol in BUG #18254 [1]. That
one was FreeBSD / LLVM 16 failing to load llvmjit.so:
```
Undefined symbol
"_ZN4llvm12MemoryBuffer7getFileERKNS_5TwineEbbbSt8optionalINS_5AlignEE"
```
I could not find anyone reporting a SIGSEGV on this path, think we are looking
at the other face of the same ABI problem when the symbol resolves, then the
call blows up.
Someone hit the same getFile() crash outside Postgres, on LLVM 16/17 - [2].
The overload takes std::optional<llvm::Align>, and the default arguments are
built at the call site. A GCC 13-built llvmjit.so and a distro libLLVM.so.17
do not have to agree on that layout. Matching the compiler that built LLVM
would avoid it, but that is not how packages are usually built: postgres often
gets GCC, LLVM comes from the distro, and the C++ details of std::optional are
not a stable contract between the two. The C API is. So I think this is worth
fixing in tree, not treating as a local toolchain footgun.
The attached patch just does what load_module() already does. Hope to see your
thoughts on this!
[1] https://postgr.es/m/[email protected]
[2]
https://stackoverflow.com/questions/78537302/segmentation-fault-when-llvmmemorybuffergetfile-on-aarch64-with-llvm16-17
Regards,
Yuriy Grigoryev
v1-0001-jit-summary-c-api.patch
Description: v1-0001-jit-summary-c-api.patch
