Open NobodyXu opened 5 months ago
TL;DR: Zig prior to 0.12.0
didn't handle linking glibc correctly if the target version was 2.32 or lower due to how these symbols were handled (not actual function calls).
You can skip the remainder of this comment, relevant details are covered in the follow-up comment.
For jj
, there was not enough information for how to reproduce the broken quickinstall
build:
With -C strip=symbols
to remove debug symbols, you'll get the same two line outputs for cargo build
/ cargo zigbuild
as I showed for the other reproduction example.
In an attempt to match the jj
build environment a bit better, I switched to zig 0.10.0
(which is what quickinstall
is using) and Rust 1.78.0
:
So... something else is going on that I'm missing... as I can't reproduce whatever else was going on 🤷♂️
Actually... I just realized the bug report wasn't about this fstat64
call at all, it was about the git paths being different / deprecated, thus the paths themselves didn't exist. (EDIT: As covered below in linked issue, the fstat64
call was misleadingly returning an errno
of 0
when the checked file path did not exist)
zig 0.11.0
is the last release it fails. Seems to have been fixed from zig 0.12.0
onwards, but I don't know if it was described in the release notes 🤔 Oh it seems like it might have been this issue (regarding errno
and fstatat64
). That aligns with the findings at the cited jj
comment 🎉
The zig issues provide reproduction in other languages, once I learned it was about errno
I could reproduce in rust too (well via unsafe libc
calls):
src/main.rs
:
// Reproduction requires building with zig < 0.12.0 and glibc target < 2.33
fn main() {
unsafe {
// Reproduction requires the checked file path to be invalid:
let filepath = std::ffi::CString::new("this_file_does_not_exist").unwrap();
let mut stat: libc::stat64 = std::mem::zeroed();
let ptr = filepath.as_ptr();
// Returns c_int, 0 is success, -1 is failure:
let ret = libc::stat64(ptr, &mut stat);
// This and other stat calls will fail in the same way:
//let ret = libc::fstatat64(libc::AT_FDCWD, ptr, &mut stat as *mut libc::stat64, 0);
let errno = std::io::Error::last_os_error();
// NOTE: `errno.raw_os_error().unwrap();` can provide just the error code itself
match ret {
// Example of working functionality when successful:
0 => {
let uid = stat.st_uid;
println!("The file is owned by UID: {uid}");
},
// The `errno` code will incorrectly be 0 (Success) despite actually failing (`ret == -1`):
_ => println!("Failure!\n| ret: {ret:?}\n| err: {errno:?}")
}
}
}
Initial environment setup:
$ docker run --rm -it fedora:41
# Add zig releases:
$ mkdir /opt/zig-11 /opt/zig-12
$ curl -fsSL https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz \
| tar -xJ -C /opt/zig-11 --strip-components=1
$ curl -fsSL https://ziglang.org/download/0.12.0/zig-linux-x86_64-0.12.0.tar.xz \
| tar -xJ -C /opt/zig-12 --strip-components=1
# Add rust:
$ dnf install -y gcc rustup nano
$ rustup-init -y --profile minimal && source "$HOME/.cargo/env"
$ cargo install cargo-zigbuild
# Prep project:
$ cargo init /tmp/example && cd /tmp/example
$ cargo add libc
# Replace main.rs with above rust snippet:
$ rm -f src/main.rs && nano src/main.rs
Here are the results:
# `ret -1` is expected, but the `err` code should be `2`, not `0` as it wasn't actually successful:
$ CARGO_ZIGBUILD_ZIG_PATH=/opt/zig-11/zig cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
$ target/x86_64-unknown-linux-gnu/release/example
Failure!
| ret: -1
| err: Os { code: 0, kind: Uncategorized, message: "Success" }
# Correct for glibc 2.33+ where the fstat symbol changed to real function calls:
$ rm -rf target
$ CARGO_ZIGBUILD_ZIG_PATH=/opt/zig-11/zig cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.33
Failure!
| ret: -1
| err: Os { code: 2, kind: NotFound, message: "No such file or directory" }
# glibc 2.32 is working correctly from zig 0.12.0+:
$ rm -rf target
$ CARGO_ZIGBUILD_ZIG_PATH=/opt/zig-12/zig cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.32
Failure!
| ret: -1
| err: Os { code: 2, kind: NotFound, message: "No such file or directory" }
Release dates for context to the October 2020 glibc change referenced below:
Related: martinvonz/jj#3844
According to this comment by @yuja
which might. be the problem.