Skip to content
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

rustc 1.59/1.60 builds musl binaries that segfault, when compiling with musl-gcc wrappers, due to static-pie default #95926

Open
joshtriplett opened this issue Apr 11, 2022 · 16 comments
Labels
C-bug Category: This is a bug. E-help-wanted Call for participation: Help is requested to fix this issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. O-musl Target: The musl libc P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-diagnostics Working group: Diagnostics

Comments

@joshtriplett
Copy link
Member

joshtriplett commented Apr 11, 2022

With the x86_64-unknown-linux-musl target installed:

$ cat hello.rs 
fn main() {
    println!("Hello, world!");
}
$ rustc hello.rs --target x86_64-unknown-linux-musl && file hello && ./hello 
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=29ba716c85a1f3f9990246f160b61003b38b63a9, with debug_info, not stripped
Hello, world!
$ rustc hello.rs --target x86_64-unknown-linux-musl -C linker=musl-gcc && file hello && ./hello 
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, with debug_info, not stripped
Segmentation fault

A gdb backtrace shows the segfault in _start_c () at ../src_musl/crt/../ldso/dlstart.c:141.

This segfault happens because the musl-gcc wrappers (including cross-compile wrappers like x86_64-linux-musl-gcc and aarch64-linux-musl-gcc) don't support static-pie in the way rustc is invoking them.

This is a regression in Rust 1.59 and 1.60; 1.58 and before produced working binaries. 1.59 includes #70740 , which not only marked the musl targets as supporting static-pie (which they may or may not depending on the linker), but also made x86_64-unknown-linux-musl default to static-pie.

For context, the musl-gcc wrappers are commonly used for a variety of reasons, including cross-compilation (particularly when linking native C code). Attempting to link using x86_64-linux-gnu-gcc or aarch64-linux-gnu-gcc cross-compilers (rather than the corresponding -musl-gcc cross-compilers) produces compatibility issues, especially with projects that build and link native C dependencies.

I noticed this problem when working with someone trying to cross-compile a project from aarch64 to x86-64, using the x86_64-linux-musl-gcc cross-compiler wrapper, installed via Debian. (I hadn't previously noticed the regression myself, because I hadn't arranged to use the cross-compiler wrappers on x86_64 since my native host is x86_64.)

This problem doesn't currently show up when cross-compiling from x86_64 to aarch64, since aarch64 doesn't use static-pie by default, but enabling PIE with -C relocation-model=pie triggers the same bug and makes the resulting binaries segfault.

I'm currently working around this, but I think this is a stable regression.

(For reference, two possible workarounds: use -C relocation-model=static, or use linker=x86_64-linux-gnu-gcc and hope it works for you.)

@joshtriplett joshtriplett added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. O-musl Target: The musl libc C-bug Category: This is a bug. labels Apr 11, 2022
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Apr 11, 2022
@joshtriplett joshtriplett added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 11, 2022
rbradford added a commit to rbradford/cloud-hypervisor that referenced this issue Apr 11, 2022
Unfortunately Rust 1.59 produces binaries that segfault when compiled
with musl-gcc wrappers. Which is exactly how we produce out aarch64 and
musl binaries for the release.

See: rust-lang/rust#95926

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
rbradford added a commit to cloud-hypervisor/cloud-hypervisor that referenced this issue Apr 11, 2022
Unfortunately Rust 1.59 produces binaries that segfault when compiled
with musl-gcc wrappers. Which is exactly how we produce out aarch64 and
musl binaries for the release.

See: rust-lang/rust#95926

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
@12101111
Copy link
Contributor

Can you provide the linker command?
It's fixed in 2018: https://git.musl-libc.org/cgit/musl/commit/?id=7dad9c212587267818de919dd9c5886f18f99779
(Unless you are using Ubuntu 18.04 which is unfixed)

@joshtriplett
Copy link
Member Author

~$ cat /usr/bin/x86_64-linux-musl-gcc
#!/bin/sh
exec "${REALGCC:-x86_64-linux-gnu-gcc}" "$@" -specs "/usr/lib/x86_64-linux-musl/musl-gcc.specs"
~$ cat /usr/lib/x86_64-linux-musl/musl-gcc.specs
%rename cpp_options old_cpp_options

*cpp_options:
-nostdinc -isystem /usr/include/x86_64-linux-musl -isystem include%s %(old_cpp_options)

*cc1:
%(cc1_cpu) -nostdinc -isystem /usr/include/x86_64-linux-musl -isystem include%s

*link_libgcc:
-L/usr/lib/x86_64-linux-musl -L .%s

*libgcc:
libgcc.a%s %:if-exists(libgcc_eh.a%s)

*startfile:
%{!shared: /usr/lib/x86_64-linux-musl/Scrt1.o} /usr/lib/x86_64-linux-musl/crti.o crtbeginS.o%s

*endfile:
crtendS.o%s /usr/lib/x86_64-linux-musl/crtn.o

*link:
-dynamic-linker /lib/ld-musl-x86_64.so.1 -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic}

*esp_link:


*esp_options:


*esp_cpp_options:


@12101111
Copy link
Contributor

LinkOutputKind::StaticNoPicExe => {
// `-static` works for both gcc wrapper and ld.
self.cmd.arg("-static");
if !self.is_ld && self.sess.target.linker_is_gnu {
self.cmd.arg("-no-pie");
}
}
LinkOutputKind::StaticPicExe => {
if !self.is_ld {
// Note that combination `-static -pie` doesn't work as expected
// for the gcc wrapper, `-static` in that case suppresses `-pie`.
self.cmd.arg("-static-pie");
} else {
// `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
// a static pie, but currently passed because gcc and clang pass them.
// The former suppresses the `INTERP` ELF header specifying dynamic linker,
// which is otherwise implicitly injected by ld (but not lld).
// The latter doesn't change anything, only ensures that everything is pic.
self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
}
}

The musl-gcc wrapper don't recongnize -static-pie/-pie/-no-pie, but do recongnize -static. The combination of -dynamic-linker and -static also break lld.

> cat hello.c
#include<stdio.h>
int main() {
  printf("Hello, world!\n");
  return 0;
}
> musl-gcc hello.c -o hello -static-pie
ld -plugin /usr/lib/gcc/x86_64-linux-gnu/10/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper -plugin-opt=-fresolution=/tmp/cciwsIZK.res -plugin-opt=-pass-through=/usr/lib/gcc/x86_64-linux-gnu/10/libgcc.a -plugin-opt=-pass-through=/usr/lib/gcc/x86_64-linux-gnu/10/libgcc_eh.a -plugin-opt=-pass-through=-lc -dynamic-linker /lib/ld-musl-x86_64.so.1 -nostdlib -pie -o hello /usr/lib/x86_64-linux-musl/Scrt1.o /usr/lib/x86_64-linux-musl/crti.o /usr/lib/gcc/x86_64-linux-gnu/10/crtbeginS.o -L/usr/lib/x86_64-linux-musl -L /usr/lib/gcc/x86_64-linux-gnu/10/. /tmp/ccNzdDMJ.o --start-group /usr/lib/gcc/x86_64-linux-gnu/10/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/10/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o /usr/lib/x86_64-linux-musl/crtn.o
> file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, with debug_info, not stripped
> musl-gcc hello.c -o hello -static
ld -plugin /usr/lib/gcc/x86_64-linux-gnu/10/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper -plugin-opt=-fresolution=/tmp/cciPPY3o.res -plugin-opt=-pass-through=/usr/lib/gcc/x86_64-linux-gnu/10/libgcc.a -plugin-opt=-pass-through=/usr/lib/gcc/x86_64-linux-gnu/10/libgcc_eh.a -plugin-opt=-pass-through=-lc -dynamic-linker /lib/ld-musl-x86_64.so.1 -nostdlib -static -o hello /usr/lib/x86_64-linux-musl/Scrt1.o /usr/lib/x86_64-linux-musl/crti.o /usr/lib/gcc/x86_64-linux-gnu/10/crtbeginS.o -L/usr/lib/x86_64-linux-musl -L /usr/lib/gcc/x86_64-linux-gnu/10/. /tmp/cckhAQSp.o --start-group /usr/lib/gcc/x86_64-linux-gnu/10/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/10/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o /usr/lib/x86_64-linux-musl/crtn.o
> file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped
 > musl-gcc -fuse-ld=lld -static hello.c -o hello
ld.lld -plugin /usr/lib/gcc/x86_64-linux-gnu/10/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper -plugin-opt=-fresolution=/tmp/cc788cAg.res -plugin-opt=-pass-through=/usr/lib/gcc/x86_64-linux-gnu/10/libgcc.a -plugin-opt=-pass-through=/usr/lib/gcc/x86_64-linux-gnu/10/libgcc_eh.a -plugin-opt=-pass-through=-lc -dynamic-linker /lib/ld-musl-x86_64.so.1 -nostdlib -static -o hello /usr/lib/x86_64-linux-musl/Scrt1.o /usr/lib/x86_64-linux-musl/crti.o /usr/lib/gcc/x86_64-linux-gnu/10/crtbeginS.o -L/usr/lib/x86_64-linux-musl -L /usr/lib/gcc/x86_64-linux-gnu/10/. /tmp/ccsEJC6i.o --start-group /usr/lib/gcc/x86_64-linux-gnu/10/libgcc.a /usr/lib/gcc/x86_64-linux-gnu/10/libgcc_eh.a -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o /usr/lib/x86_64-linux-musl/crtn.o
> file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, interpreter /lib/ld-musl-x86_64.so.1, with debug_info, not stripped
> ./hello
zsh: segmentation fault  ./hello

Fedora fix this https://src.fedoraproject.org/rpms/musl/blob/rawhide/f/musl-1.2.0-Support-static-pie-with-musl-gcc-specs.patch and Debian don't have this patch.

@apiraino
Copy link
Contributor

apiraino commented Apr 13, 2022

thanks @12101111 for the investigation. This looks like a distro specific issue that should be probably handled by them, correct? Just trying to understand if there's an actionable on our side.

@12101111
Copy link
Contributor

Yes, we can't fix the broken wrapper in our side ( we can detect it but can't fix it expect creating a new wrapper).

@joshtriplett
Copy link
Member Author

joshtriplett commented Apr 13, 2022

@apiraino The action on the Rust side would be to roll back the use of this by default until it's more widely supported. Or, alternatively, attempt to detect the use of the wrapper and roll it back in that circumstance, but that seems fraught.

@joshtriplett
Copy link
Member Author

(Also, long-term, we could fix this by making the wrappers not necessary anymore for cross compiling with musl.)

@apiraino
Copy link
Contributor

Assigning priority as discussed in the Zulip thread of the Prioritization Working Group.

@rustbot label -I-prioritize +P-high

@rustbot rustbot added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Apr 14, 2022
rbradford added a commit to rbradford/cloud-hypervisor that referenced this issue May 23, 2022
This reverts commit 6a09925.

It is now clear that pinning the toolchain for cross compilation is not
necessary since we only use it for building to aarch64:

rust-lang/rust#95926 (comment)

"This problem doesn't currently show up when cross-compiling from x86_64
to aarch64, since aarch64 doesn't use static-pie by default, but
enabling PIE with -C relocation-model=pie triggers the same bug and
makes the resulting binaries segfault."

Fixes: cloud-hypervisor#3962

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
rbradford added a commit to cloud-hypervisor/cloud-hypervisor that referenced this issue May 23, 2022
This reverts commit 6a09925.

It is now clear that pinning the toolchain for cross compilation is not
necessary since we only use it for building to aarch64:

rust-lang/rust#95926 (comment)

"This problem doesn't currently show up when cross-compiling from x86_64
to aarch64, since aarch64 doesn't use static-pie by default, but
enabling PIE with -C relocation-model=pie triggers the same bug and
makes the resulting binaries segfault."

Fixes: #3962

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
apestel added a commit to apestel/boursoscrap that referenced this issue Aug 9, 2022
@ghost
Copy link

ghost commented Aug 14, 2022

This seems possibly related to two issues I've been having:
deltaphc/raylib-rs#119
gtk-rs/gtk4-rs#1096

But when I try to follow this example, the second command gives me:

error: linker `musl-gcc` not found
  |
  = note: No such file or directory (os error 2)

error: aborting due to previous error

@pnkfelix
Copy link
Member

Discussed at P-high review

At this point I doubt we would roll-back the default setting, at least not silently. (Maybe via an MCP or something, if there was a push.)

But I suspect the best short term act to take would be a diagnostic warning when we attempt to compile with the known-to-be-problematic combination of flags? @joshtriplett would that satisify you here?

@joshtriplett
Copy link
Member Author

@pnkfelix Some kind of detection and warning would be helpful at a minimum, yes.

@pnkfelix pnkfelix added the E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. label Apr 14, 2023
@pnkfelix
Copy link
Member

pnkfelix commented Apr 14, 2023

Discussed at 2023-Q1 P-high review

I'm willing (*) to mentor someone who would like to add the aforementioned detection+issuing-of-diagnostic of the problematic combination of flags.

I'm mainly wondering whether doing so will be E-easy, or E-medium.

(*): However, I will be away from computers for a week, coming back on 2023-04-24. So not available to mentor until late April at earliest. You can probably find someone who can assist. I'll try to write up some guidance in the meantime.

@pnkfelix pnkfelix added the E-help-wanted Call for participation: Help is requested to fix this issue. label Apr 14, 2023
@Timmmm
Copy link
Contributor

Timmmm commented Aug 29, 2023

or use linker=x86_64-linux-gnu-gcc

I don't understand this whatever this is about, but in case this helps anyone here, I used to set

CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-linux-musl-gcc

And it totally worked, but now it causes a segfault. Both -C relocation-model=static and -C target-feature=-crt-static led to linker errors, but in the end I tried unsetting that environment variable and it just works now. I can't really remember why it was needed years ago but apparently it isn't now.

@wesleywiser wesleywiser added the WG-diagnostics Working group: Diagnostics label Nov 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. E-help-wanted Call for participation: Help is requested to fix this issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. O-musl Target: The musl libc P-high High priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-diagnostics Working group: Diagnostics
Projects
None yet
Development

No branches or pull requests

8 participants
@joshtriplett @pnkfelix @Timmmm @wesleywiser @apiraino @12101111 @rustbot and others