Skip to content

Minimum Supported glibc version #1412

Open
@gnzlbg

Description

@gnzlbg

IIRC, the current minimum supported glibc version on x86_64-unknown-linux-gnu is 2.26. We offer APIs that are only available in glibc 2.27 and 2.28 though. When used, those API would crash on glibc 2.26, but if they are not used, everything is ok.

That is, we support glibc >= 2.26, where some APIs are "backward-compatible" extensions.

However, some new features in newer glibc versions (e.g. shadow stack in glibc 2.28, see #1410 ) are ABI incompatible with older glibc versions (e.g. the layout of a struct changes). That is, adding support for these features introduces undefined behavior in Rust programs that are dynamically linked against older glibc versions. These types of changes happen super often, e.g., glibc adds a new field to a struct, and newer glibc versions support code compiled against older versions, but the opposite is not true. Essentially, libc is like a C header file of a particular libc version, but with stuff mixed in from future versions on top.

We should:

  • document the minimum glibc version
  • have a policy for bumping the minimum supported glibc version (cc @rust-lang/libs)

Most crates use libc via crates.io, and not via the Rust toolchain, so we can't use crater to test breaking changes AFAIK. Upgrading the minimum glibc version is bad, because it introduces undefined behavior silently into working Rust programs. Not upgrading the minimum glibc version is bad, because we can't expose newer features to users, and because code that uses newer backward-compatible features has undefined behavior if the minimum supported version is dynamically linked. It also has the downside that when the distros that use that particular glibc version go end-of-life, testing libc becomes harder (e.g. CI needs to work around this, and force Rust programs to be linked to the minimum supported glibc version even if the system has a newer one).

I don't know of any solution that does not have serious downsides. Right now, the policy for upgrading the minimum glibc version is "try it out, and if nobody complains, then the upgrade was ok". But since the UB is introduced silently, it takes a while for people to notice when it happens.

The only safe solution I know would be to just support glibc 2.0, and not add any APIs that are not available there, ever. Right now this means that we would need to remove a lot of APIs, which would also be a significant breaking change. We could layer backward compatible APIs on top, and like we do right now, lay the burden of proving that the dynamically linked glibc version is new enough to users.

The way some libraries try to solve this problem is by using cargo features to pick a library version. So, e.g., if we had a glibc crate, we could have a version 2.0 of it, and then use features like cargo build --feature v2.28 or cargo build --feature v2.0, etc. to pick up the minimum glibc version that should be targeted (a build.rs figures out the version required from the passed features - e.g. the latest version passed). If a glibc 3.0 is ever released, we would release a breaking version to crates.io and linking both would be incompatible. This would mean that somehow, the glibc version used by libstd, would need to be transparently overridden if a different one is required by the dependency graph, and libstd recompiled with it (solutions to these problem are being discussed in #570) .

Doing this for libc would be a mess, because libc supports dozens of C libraries, so we'd need to add features for all of those. We'd probably need to split libc into smaller crates, wrapping a single library each (glibc, musl, libSystem, ...).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions