Skip to content

Linking a Rust staticlib unexpectedly changes C math functions from libm to bundled ones from compiler-builtins #142119

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
durin42 opened this issue Jun 6, 2025 · 6 comments
Labels
A-compiler-builtins Area: compiler-builtins (https://github.com/rust-lang/compiler-builtins) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. I-prioritize Issue: Indicates that prioritization has been requested for this issue. 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. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@durin42
Copy link
Contributor

durin42 commented Jun 6, 2025

Code

Given a staticlib with the source:

#[unsafe(no_mangle)]
pub extern "C" fn demo() -> f32 {
    let x : f32 = 1.1;
    x.ceil()
}

compiled as crate-type = ["staticlib"] and the C program:

#include <math.h>
#include <stdio.h>

float demo();

int main(int argc, char** argv) {
    float x = -1.2;
    printf("%f\n", ceilf(x));
    printf("%f\n", demo());
    return 0;
}

When linking the program like this: $(CC) main.o as-crate/target/debug/libas_crate.a -lm -o out/tgt-from-crate the resulting binary ends up using ceilf from compiler-builtins rather than libm.

I expected to see this happen: The binary should still get ceilf from libm, eg

$ nm -uD out/tgt-from-crate | grep ceilf || true
                 U ceilf@GLIBC_2.2.5

Instead, this happened: Instead, the ceilf symbol was satisfied by the matching symbol in compiler-builtins, and so the C call was surprise-migrated to a different implementation.

Version it worked on

1.86
rustc --version --verbose:

rustc 1.86.0 (05f9846f8 2025-03-31)
binary: rustc
commit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb
commit-date: 2025-03-31
host: x86_64-unknown-linux-gnu
release: 1.86.0
LLVM version: 19.1.7

Version with regression

1.87
rustc --version --verbose:

rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: x86_64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1

Additional information

I suspect this is related to some work tracked in #137578. I also found out Chromium has already stumbled on this: https://issues.chromium.org/issues/419258012#comment5 and for them it caused observable behavior changes. Apologies for not catching this sooner - we hadn't upgraded compiler-builtins for a while and didn't notice until a couple of weeks ago. :(

@durin42 durin42 added C-bug Category: This is a bug. regression-untriaged Untriaged performance or correctness regression. labels Jun 6, 2025
@rustbot rustbot added needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 6, 2025
@jieyouxu

This comment has been minimized.

@tgross35

This comment has been minimized.

@Noratrieb Noratrieb added A-linkage Area: linking into static, shared libraries and binaries A-compiler-builtins Area: compiler-builtins (https://github.com/rust-lang/compiler-builtins) and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jun 8, 2025
@Noratrieb
Copy link
Member

bisection script

#!/usr/bin/env bash

set -ex

rustc --crate-type=staticlib a.rs
cc main.c liba.a -lm -o main

not nm -uD main | rg ceilf

searched nightlies: from nightly-2024-05-01 to nightly-2025-05-20
regressed nightly: nightly-2025-03-06
searched commit range: f9e0239...30f168e
regressed commit: ac951d3

bisected with cargo-bisect-rustc v0.6.8

Host triple: x86_64-unknown-linux-gnu
Reproduce with:

cargo bisect-rustc github --start 2024-05-01 --end 2025-05-20 --script repro.sh 

rust-lang/compiler-builtins#763

@Noratrieb
Copy link
Member

It looks like rust-lang/compiler-builtins#763 just doesn't work, even a normal rust main reproducer picks ceilf from compiler-builtins instead of libc.

fn main() {
    let x : f32 = std::hint::black_box(1.1);
    dbg!(x.ceil());
}
nora@nixos /t/scratchBGHE6xUbh> rustc a.rs
nora@nixos /t/scratchBGHE6xUbh> nm -uD a | rg ceil
nora@nixos /t/scratchBGHE6xUbh [0|1]> rustc +1.84.1 a.rs
nora@nixos /t/scratchBGHE6xUbh> nm -uD a | rg ceil
                 U ceilf@GLIBC_2.2.5

@Noratrieb
Copy link
Member

I'm a bit confused, this case for pure-rust programs was reported in #139487 but closed. But rust-lang/compiler-builtins#763 intended to not override anything, so that still seems like a bug? This here is just an extension of it where it will infect FFI as well, instead of just Rust.
@tgross35 is it intended that Rust programs now always call the compiler-builtins version?

@Noratrieb Noratrieb added regression-from-stable-to-stable Performance or correctness regression from one stable version to another. and removed regression-untriaged Untriaged performance or correctness regression. labels Jun 8, 2025
@jieyouxu jieyouxu added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jun 8, 2025
@Noratrieb
Copy link
Member

#137578 (comment) @Amanieu

So I previously thought that statically linked weak symbols always override strong dynamic symbols, but this may not actually be the case

It is indeed not the case. https://gist.github.com/Noratrieb/a58000d43527225ed5af0032890e00a5
This prints eak, so the weak symbol, instead of uwu, which would be the strong dynamic symbol.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-compiler-builtins Area: compiler-builtins (https://github.com/rust-lang/compiler-builtins) A-linkage Area: linking into static, shared libraries and binaries C-bug Category: This is a bug. I-prioritize Issue: Indicates that prioritization has been requested for this issue. 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. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants