Skip to content

PIE+LTO causes Bitcoin-Qt to segfault at startup #867

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
whitslack opened this issue Apr 22, 2025 · 14 comments
Open
1 task done

PIE+LTO causes Bitcoin-Qt to segfault at startup #867

whitslack opened this issue Apr 22, 2025 · 14 comments

Comments

@whitslack
Copy link
Contributor

Issues, reports or feature requests related to the GUI should be opened directly on the GUI repo

  • I still think this issue should be opened here

Report

When PIE and LTO are combined, Qt applications crash at startup. See Gentoo bug 954171. You can read all the gorey details about the underlying issue (that also affected Wireshark) here. Basically, the issue is that Qt's qcompilerdetection.h prohibits building Qt with PIE because PIE breaks a critical assumption that Qt makes, but when a Qt application is built using LTO, the application's -fPIE flag overrides Qt's -fPIC flag and causes pieces of Qt to be optimized under the PIE model, which breaks it and causes it to segfault at runtime. The guard in qcompilerdetection.h is powerless to detect and prevent this because it's implemented by a preprocessor directive, and the preprocessor is not involved during LTO. To fix this, Bitcoin-Qt has to choose either LTO or PIE but not both. In Gentoo we plan to work around this for now by filtering out -flto from the user's flags, but it would be nicer to have an upstream solution.

@eli-schwartz
Copy link

To be clear, the actual issue is that cmake has POSITION_INDEPENDENT_CODE, which claims to implement PIC, but it does not. It enables PIE instead, which is not what you actually asked for, and they are unfortunately different enough to matter.

It's quite fine to enforce -fPIC (and also to link with -pie), but cmake simply does not provide the necessary builtin functionality to do it correctly.

@hebasto
Copy link
Member

hebasto commented Apr 22, 2025

  1. It seems reasonable to move this issue to the main repository to increase its visibility to the build system developers.

  2. I can't reproduce the issue on Ubuntu 24.10 using GCC 14.2.0:

$ rm -rf build && cmake -B build -DCMAKE_C_FLAGS=-flto -DCMAKE_CXX_FLAGS=-flto -DBUILD_GUI=ON
$ cmake --build build -t bitcoin-qt
$ ./build/bin/bitcoin-qt

This suggests the issue may be specific to the default compiler options. If so, please consider updating the OP accordingly.

  1. Based on several related discussions, the root cause appears to lie upstream—with Qt and / or CMake:

@thesamesam
Copy link

Ubuntu builds their Qt with "reduce relocations" disabled, so it doesn't hit this (see https://bugs.gentoo.org/933110#c5).

The root cause is a mix between Qt, CMake, and the fact there's no way for the toolchain to communicate a problem. CMake doesn't seem particularly interested in fixing it given https://gitlab.kitware.com/cmake/cmake/-/issues/15570#note_477736. Qt says that the right thing to do is to honour their own recommendation (naturally).

I spent a significant amount of time investigating it and I really don't see an option besides changing CMake (and CMake doesn't seem interested) than fixing upstream projects which use Qt to simply not use POSITION_INDEPENDENT_CODE and replace it with inlined -fPIC where appropriate and -pie at link-time.

@fanquake
Copy link
Member

I remember us already having code to work around something similar to this. i.e: https://github.com/bitcoin/bitcoin/blob/dbc450c1b59b24421ba93f3e21faa8c673c0df4c/build-aux/m4/bitcoin_qt.m4#L182? Looks like it was just dropped, rather than ported to CMake?

@hebasto
Copy link
Member

hebasto commented Apr 22, 2025

I remember us already having code to work around something similar to this. i.e: https://github.com/bitcoin/bitcoin/blob/dbc450c1b59b24421ba93f3e21faa8c673c0df4c/build-aux/m4/bitcoin_qt.m4#L182? Looks like it was just dropped, rather than ported to CMake?

Was it related to LTO?

@thesamesam
Copy link

thesamesam commented Apr 22, 2025

It's the same problem. It just shows up worse with LTO because Qt's sanity check can't fire to tell you (at the point where the preprocessor is run, the right flags are in effect) and give you a build failure instead.

The way that CMake handles this (which is buggy, at least for Qt) means it doesn't show up without LTO, because it does pass -fPIC almost all of the time, just not the whole time (does -fPIE when linking). If CMake just did -fPIE for everything, you'd get an error instead.

@hebasto
Copy link
Member

hebasto commented Apr 23, 2025

Is anyone aware of other distros that provide shared Qt libraries built with -reduce-relocations?

(asking because I'm not quite familiar with Gentoo)

Fedora, Debian/Ubuntu, and Arch do not have such an issue.

@thesamesam
Copy link

thesamesam commented Apr 23, 2025

Fedora, Debian/Ubuntu, opensuse, Alpine disable it. Arch disables it but only for Qt 5 AFAICT (has it enabled for Qt 6). Looks like Void has it on.

@hebasto
Copy link
Member

hebasto commented Apr 23, 2025

Arch disables it but only for Qt 5 AFAICT (has it enabled for Qt 6).

Building on Arch with -flto does not expose any runtime issues (obviously, using Qt 6).

@thesamesam
Copy link

@hebasto
Copy link
Member

hebasto commented Apr 23, 2025

@whitslack @eli-schwartz @thesamesam

Setting the required conditions aside, can you confirm whether the following patch resolves the issue on Gentoo:

--- a/src/qt/CMakeLists.txt
+++ b/src/qt/CMakeLists.txt
@@ -250,6 +250,8 @@ if(qt_lib_type STREQUAL "STATIC_LIBRARY")
   )
 endif()
 
+list(TRANSFORM CMAKE_CXX_LINK_OPTIONS_PIE REPLACE "${CMAKE_CXX_COMPILE_OPTIONS_PIE}" "${CMAKE_CXX_COMPILE_OPTIONS_PIC}")
+
 add_executable(bitcoin-qt
   main.cpp
   ../init/bitcoin-qt.cpp

?

@hebasto
Copy link
Member

hebasto commented Apr 23, 2025

Interesting! It should happen since https://gitlab.archlinux.org/archlinux/packaging/packages/qt6-base/-/commit/5cd71aed56de955b182e20263a50cd91bf7b6aaa.

This approach appears suitable for Gentoo's Qt packages as well, since, according to this commit message, the -Bsymbolic and -Bsymbolic-functions functionality—underlying the -reduce-relocations option—is broken.

@joecool1029
Copy link

@hebasto I can confirm the above resolves the issue. (I am the Gentoo bug reporter on this)

@thesamesam
Copy link

This approach appears suitable for Gentoo's Qt packages as well [...]

Yes, this is the conclusion I reached as well. The original Qt commit adding the improved version didn't have it optional, and I saw it referenced in headers which made me think the feature detection had enabled it -- but it only detected it, didn't enable it unless passed explicitly, as a followup Qt commit (a while later) disabled it until newer Binutils is widely adopted, I think.

Anyway, you're absolutely right, and it's indeed a fix for us: we're adopting the no-direct-extern-access Qt option which fixes reduce-relocations.

I think the fix you mention is right for the reduce-relocations case, though (just that we in Gentoo, and anyone else using reduce-relocations, are best off using that newer feature on top to avoid hitting issues like this). Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants