rust-lang / rust-semverver

Automatic checking for semantic versioning in library crates
BSD 3-Clause "New" or "Revised" License
638 stars 41 forks source link

ABI compatibility checking #40

Open mzabaluev opened 6 years ago

mzabaluev commented 6 years ago

If and when the Rust stable ABI becomes a reality, there should be tool support to check dylib crates for breaking and major changes in the ABI.

oli-obk commented 6 years ago

Why would we need a stable abi? Just using the same compiler for both compilation runs should produce comparable abi, right?

mzabaluev commented 6 years ago

@oli-obk

Why would we need a stable abi?

Rust has had support for dynamic library crates since before 1.0, it's just not the default output for a library crate, and the Cargo build system is currently geared towards static linkage. But to make dylibs practical in a software distribution, the ABI must not break between different compiler releases, unless the Rust major version changes.

oli-obk commented 6 years ago

I misunderstood the issue. Sorry. Everything makes sense now ;)

gnzlbg commented 5 years ago

Rust does not have a stable ABI, and for all we know it might never have one. It might make sense to close this issue for the time being, since it isn't really actionable, and re-open it if Rust ever gets a stable ABI.

zrneely commented 5 years ago

It seems that right now, the only way to be sure of ABI compatibility when loading a dynamic library is to either expose the dynamic library's functions via a C API, or to ensure that both the loader and loadee were built with exactly the same version of rustc (down to the minor version, since even nightly builds could change the ABI).

It would be great if there could be a semver-backed guarantee of ABI compatibility between rustc versions in the future, but that doesn't seem to be possible now.

gnzlbg commented 5 years ago

It would be great if there could be a semver-backed guarantee of ABI compatibility between rustc versions in the future, but that doesn't seem to be possible now.

What do you mean by a semver-backed guarantee? Do you mean that the artifacts produced by two different Rust toolchains should be ABI compatible (as long as the semver version of the ABI is the same) ?

gnzlbg commented 5 years ago

Note that Rust guarantees that the "rust" ABI of each Rust toolchain is incompatible with that of all other toolchains. This is an explicitly designed language feature.

If you want a stable ABI for interoperation, repr(C)/extern "C" are some of the language features that allow you to write that. If you use those in your library API, you are guaranteed ABI compatibility.

rust-semverver only checks whether the APIs are semver compatible. If your exported API exports only repr(C) types / extern "C" functions, then API compatibility might mean ABI compatibility (not 100% sure, but feels right to me). We could add a lint to clippy that warns / errors if exported APIs aren't repr(C)/extern "C" but that's an issue that belongs in the clippy repo.

zrneely commented 5 years ago

Sorry, to clarify, I mean that my ideal world is: two versions of rustc whose semver version numbers indicate that they're compatible (0.2 and 0.3, for example, or 1.2.5 and 1.6.10) would be guarateed to have ABI compatibility.

I understand that's significantly different than the current model, and that it imposes strict restrictions on future ABI changes and improvements. I'm not suggesting that my proposal is the right balance of tradeoffs :)

ibabushkin commented 5 years ago

On 2019-03-15, Zachary Neely wrote:

Sorry, to clarify, I mean that my ideal world is: two versions of rustc whose semver version numbers indicate that they're compatible (0.2 and 0.3, for example, or 1.2.5 and 1.6.10) would be guarateed to have ABI compatibility.

I understand that's significantly different than the current model, and that it imposes strict restrictions on future ABI changes and improvements. I'm not suggesting that my proposal is the right balance of tradeoffs :)

-- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: https://github.com/rust-dev-tools/rust-semverver/issues/40#issuecomment-473355661

Independtly from that, this is not something we can properly implement in rust-semverver as of now, sadly.

gnzlbg commented 5 years ago

@zrneely Rust semver numbers are about the Rust programming language itself, not about the ABI of Rust binaries.

The ABI of Rust binaries follow a different semver versioning. The ABI of each toolchain is incompatible with that of every other by design, so the ABI semver version of Rust 1.23.0 might be 1234.0.0 and the one of Rust 1.23.1 might be 5678.0.0. The major version number itself does not matter, what matters is that they are all different (not only the released versions, but also each nightly has a different ABI from all other nightlies and Rust releases).

As mentioned, this is a feature of the language. Changing / removing this feature would need RFCs that go through the process. That probably will never happen, but even if it does, until that happens there is nothing that can be done here.

ehiggs commented 2 years ago

If you want a stable ABI for interoperation, repr(C)/extern "C" are some of the language features that allow you to write that. If you use those in your library API, you are guaranteed ABI compatibility.

This issue should be focused on supporting exactly this to make sure the ABI is something that can be verified.

Strawman starting place to knockdown:

If not building as dynlib, the ABI are not equivalent (always tick minor version - never patch version).

If building as dynlib and repr(C) is not used, then the ABIs are the same (no exported functions).

If building as dynlib and repr(C) is used, then check exported struct sizes are the same with no reorderings and make sure no functions were deleted or no function arguments changed order; if an argument was added to a function make sure it's not used). If these checks pass, they are ABI equivalent.

With regards to files being saves and reopened (e.g. scratch files, sqlite files to maintain state... not sure how to do that; but catching the above would be good)