nix icon indicating copy to clipboard operation
nix copied to clipboard

cfgetospeed(): called `Result::unwrap()` on an `Err` value: EINVAL

Open julian-klode opened this issue 3 months ago • 16 comments

Given

use nix::sys::termios::{
    cfgetospeed, tcgetattr
};

fn main() {
    let stdin = std::io::stdin();
    let termios = tcgetattr(stdin).expect("Could not get terminal attributes");
    let speed = cfgetospeed(&termios);
    println!("{:?}", speed);
}

We receive:

> cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/demo`

thread 'main' panicked at /home/jak/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/nix-0.30.1/src/sys/termios.rs:767:70:
called `Result::unwrap()` on an `Err` value: EINVAL
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

with glibc 2.42

(Minimized reproducer of https://github.com/uutils/coreutils/issues/8474)

julian-klode avatar Sep 04 '25 20:09 julian-klode

Not sure why though given that when I strace it I see no EINVAL at all and get:

ioctl(0, TCGETS2, {c_iflag=BRKINT|ICRNL|IMAXBEL, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|B38400<<IBSHIFT|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0

julian-klode avatar Sep 04 '25 21:09 julian-klode

It seems that glibc 2.42 has migrated from the baud encoding with the B variables to the BSD approach:

jak@jak-t14-g3 /t/demo (main)> cat a.c
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    struct termios termios;
    errno = 0;
    if (tcgetattr(STDIN_FILENO, &termios))
        perror("tcgetattr");
    if (errno != 0)
        perror("tcgetattr");
    speed_t speed = cfgetospeed(&termios);
    if (errno != 0)
        perror("cfgetospeed");

    printf("%u %u\n", speed, B38400);
}
jak@jak-t14-g3 /t/demo (main)> ./a.out
38400 38400

julian-klode avatar Sep 04 '25 21:09 julian-klode

@hpax is the same issue as Possible regression in 2.42 termios refactoring re non-standard baud rate ? Do you have a suggested fix?

loqs avatar Sep 13 '25 17:09 loqs

It sounds like this is not an issue with Nix itself, right?

asomers avatar Sep 13 '25 21:09 asomers

No this is a problem in Nix, in glibc 2.42 or newer it needs to use the same code paths as bsd, only older versions of glibc use the current Linux code paths.

julian-klode avatar Sep 13 '25 21:09 julian-klode

I do not know if you can match the glibc version when building the crate but it's a must to support both old glibc and new

julian-klode avatar Sep 13 '25 21:09 julian-klode

I do not know if you can match the glibc version when building the crate but it's a must to support both old glibc and new

We can't, because glibc is a shared library and according to Bugzilla, upgrading glibc alone is enough to trigger the bug. So it's not possible for Nix to anticipate at compile-time which version of glibc it will be used with.

glibc made a backwards-incompatible change in a patch release. That's almost guaranteed to cause trouble. I'll accept a patch if you can provide one. Is there any code that works with both the old and new glibc versions?

asomers avatar Sep 13 '25 21:09 asomers

Could you use the C function gnu_get_libc_version() to determine the version at runtime? @thesamesam any suggestions?

loqs avatar Sep 13 '25 23:09 loqs

How are you invoking glibc? The glibc symbols are versioned for a reason. If you are going to invoke the ABI directly without using the header-provided information, then you should look at the symbol versions. Structure formats and types can also change; in fact, in this case they have for MIPS and SPARC.

I hate to say it, but this seems to me to be a much more serious problem in how you manage your API translation layer. Now, there are several options available to you:

  1. Detect and, if present, use the baud_t (cfsetobaud() et al) functions in glibc 2.42+
  2. Probe the Bxxx symbols from the appropriate header file. If they are equal to their numeric value, then the translation is trivial (for Linux, B300 == 300 is enough of a test.)
  3. Observe the version number of the cfsetospeed() etc symbols.
  4. Use a C shim layer.
  5. Ignore libc and directly interface with the kernel. NOT recommended – out of those that have tried, most implementations have been seriously buggy.

hpax avatar Sep 16 '25 01:09 hpax

I didn't realize that glibc used versioned symbols. But if if does, then that's definitely the best solution. You need to make a PR to https://github.com/rust-lang/libc to add #[link_name] attributes to all of the symbols whose versions have changed. libc has a policy of maintaining backwards-compatibility with some specific glibc version (I can't remember which).

asomers avatar Sep 16 '25 02:09 asomers

Well, I'm not a Rust user, but it seems that you have an idea what you need to do. The new API is enabled with GLIBC_2.42; the versions for older glibc seems to be somewhat platform-based. Note that using the old API comes with a serious loss of functionality, so you would really want to use the new one if available.

hpax avatar Sep 16 '25 02:09 hpax

Note that this might work for functions, but the baud rate constants can not be adjusted this way. They are not symbols in the ELF file, they're compile time constants.

Programs using the baud rate constants are all going to be broken by upgrading glibc.

/edit: Ah, this is not true.. they would keep calling the old functions that actually support the old baud rate constants.

de-vri-es avatar Sep 16 '25 08:09 de-vri-es

Question as a end user: is https://github.com/uutils/coreutils/issues/8474#issuecomment-3591504418 a valid workaround?

oech3 avatar Nov 29 '25 12:11 oech3

Cannot use BSD's code path and https://docs.rs/glibc_version/latest/glibc_version/ ? (Not sure what does it return on cross build) [Edit] Oh... Binary linked with old glibc would not work with this...

oech3 avatar Nov 30 '25 11:11 oech3

Smart way is to link a simple symbol reference, look at the version of the symbol picked and then pick the proper constants probably

julian-klode avatar Nov 30 '25 11:11 julian-klode