Skip to content

libc should let you manage errno #47

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

Closed
steveklabnik opened this issue Nov 7, 2015 · 13 comments
Closed

libc should let you manage errno #47

steveklabnik opened this issue Nov 7, 2015 · 13 comments

Comments

@steveklabnik
Copy link
Member

Originally filed as rust-lang/rust#17714

@kamalmarhubi
Copy link
Contributor

There's also some discussion at rust-lang/rust#18642

@alexcrichton alexcrichton changed the title libc should let you set errno libc should let you manage errno Feb 11, 2016
@nodakai
Copy link
Contributor

nodakai commented Apr 3, 2016

+1 for fn errno() -> c_int and fn set_errno(c_int). We already have a fundamental semantic gap between Rust and C here, so there's no point in sticking to literally the same identifiers with the C language spec.

I believe there are several C APIs for which checking errno is the best way to detect their errors, so clearing errno beforehand can be an essential requirement. For example... well... strtol(3) with base!=10?

@kamalmarhubi
Copy link
Contributor

I'd like us to fix this too. Another use case is writing libraries in Rust that expose a C ABI interface using errno for error signalling.

@kamalmarhubi
Copy link
Contributor

In nix, we have an errno module that provides errno() -> i32 across unix platforms. We don't have a set_errno() function though.

@alexcrichton
Copy link
Member

This library's scope is now defined by an RFC so if these sorts of function as such exist in libc on various platforms then we can certainly bind them, otherwise it'll be up to an external crate to add extra "rustic handling" for these functions.

Currently we don't necessarily keep an issue for all APIs we'd like to implement, so I'm going to close this, but PRs are always welcome!

@nodakai
Copy link
Contributor

nodakai commented Apr 3, 2016

@alexcrichton

if these sorts of function as such exist in libc on various platforms then we can certainly bind them,

I assume you didn't mean a "C function" for which libc.so has a symbol here, because the RFC
includes "C macros" such as CPU_ZERO() in its target.

POSIX states

The value of errno shall be defined only after a call to a function for which it is explicitly stated to be set and until it is changed by the next function call or if the application assigns it a value.

(emphasis mine.)

So assignment to the lvalue errno is a part of the public interface of what you call libc. Given that C's notion of "lvalue" doesn't readily map to Rust's (especially when we consider memory safety and multithreading,) and errno is typically implemented as a C macro, it would best fit with the spirit of the RFC to provide a setter function fn set_errno().

So the topic is not about "rustic handling." It's about whether you can handle it or not with the libc crate.

And again, because the original C interface based on a "lvalue" doesn't readily map to Rust, it is definitely worth having a discussion on the interface here. You shouldn't simply close this ticket.

I'd even say it is __errno_location() which should be removed from the libc crate because it is merely an implementation detail. The glibc reference doesn't even spend a word on it.

Do you think it makes more sense to define a Rust macro which closely mimics the typical errno macro (in C)? I don't think so.

extern {
    fn malloc(n: usize) -> *mut i8;  // just for an experiment
    pub fn __errno_location() -> *mut i32;  // implementation detail, but it has to be pub
}

macro_rules! errno {
    () => (
        *__errno_location()
    )
}

fn main() {
    println!("{:?}", unsafe { malloc(1 << 63) });  // sets errno
    println!("{}", unsafe { errno!() });
    unsafe { errno!() = 0 };
    println!("{}", unsafe { errno!() });
}

@sorear
Copy link

sorear commented Apr 3, 2016

Strongly agree that any library whose scope includes access to standard C library functions should include a way to set errno to 0. Both POSIX:

An application that needs to examine the value of errno to determine the error should set it to 0 before a function call, then inspect it before a subsequent function call.

and C99:

Thus, a program that uses errno for error checking should set it to zero before a library function call, then inspect it before a subsequent library function call. Of course, a library function can save the value of errno on entry and then set it to zero, as long as the original value is restored if errno’s
value is still zero just before the return. (§7.5, footnote 176)

don't merely permit modifying errno, they specify that applications and user-created libraried should do it under certain situations. Furthermore, neither of them permits referencing __errno_location (declaring an identifier with two leading underscores is undefined behavior).

In every implementation I know of, &errno is legal, but this does not seem to be guaranteed by either C or POSIX (I can't find anything that would forbid struct __thread_state { ...; signed int __errno: 14; ... }; extern struct __thread_state *__current_thread(); #define errno (__current_thread()->__errno)). errno = 0; and errno = ENOENT; are legal by spec though.

So, given that the scope of libc in RFC1291 includes "C macros" and "C statics", and errno is usually one or the other of those, and the specified interface to errno allows and in some cases requires assigning to errno, I would argue that our binding to errno is objectively incomplete and this is a needed improvement.

@bluss
Copy link
Member

bluss commented Apr 3, 2016

Can crate libc even implement setting errno properly without compiling a C shim for it? Without shim it requires all the platforms to provide something like __errno_location. If a shim is needed, it makes sense to use a separate crate to provide it.

@sorear
Copy link

sorear commented Apr 3, 2016

@bluss

  1. You could make exactly the same argument about get_errno. Are you willing to state that Rust code using the libc crate should have no access of any kind to errno?
  2. AFAICT, all Rust-supported POSIXy platforms do provide something like __errno_location; glibc and musl call it that, Android/bionic has __errno (not bound by the libc crate?), FreeBSD has __error, OpenBSD has __errno. VS CRT documents a _errno.
  3. My interpretation of RFC1291 is that a Rust program using the libc crate should be approximately as portable as the corresponding C program. So we shouldn't do anything about the fact that different platforms have different Exxx constants, but we should provide read and write access to the errno variable, because C programs can use errno without knowing how it is #defined.

@bluss
Copy link
Member

bluss commented Apr 3, 2016

  1. I said the opposite in issue Should let you get errno #81

kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/libc that referenced this issue Apr 4, 2016
kamalmarhubi added a commit to kamalmarhubi/rfcs that referenced this issue Apr 4, 2016
Without these functions, Rust programs cannot inspect errors returned by
functions defined in `libc`. From POSIX [0]:

> An application that needs to examine the value of errno to determine
> the error should set it to 0 before a function call, then inspect it
> before a subsequent function call.

From the C standard [1]:

> Thus, a program that uses errno for error checking should set it to
> zero before a library function call, then inspect it before a
> subsequent library function call.

While most `libc` functions return a sentinel value to indicate an
error, not all do. For example, POSIC `strtol` has an error condition
that can only be discovered by setting and reading `errno` [2]:

>  If the value of base is not supported, 0 shall be returned and errno
>  shall be set to [EINVAL].

Refs rust-lang/libc#47

[0] http://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html#tag_16_110_07
[1] §7.5, footnote 202 of ISO/IEC 9899:2011, WG14 draft version N1570
    (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)
[2] http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html#tag_16_590_04
kamalmarhubi added a commit to kamalmarhubi/rfcs that referenced this issue Apr 4, 2016
Without these functions, Rust programs cannot inspect errors returned by
functions defined in `libc`. From POSIX [0]:

> An application that needs to examine the value of errno to determine
> the error should set it to 0 before a function call, then inspect it
> before a subsequent function call.

From the C standard [1]:

> Thus, a program that uses errno for error checking should set it to
> zero before a library function call, then inspect it before a
> subsequent library function call.

While most `libc` functions return a sentinel value to indicate an
error, not all do. For example, POSIC `strtol` has an error condition
that can only be discovered by setting and reading `errno` [2]:

>  If the value of base is not supported, 0 shall be returned and errno
>  shall be set to [EINVAL].

Refs rust-lang/libc#47

[0] http://pubs.opengroup.org/onlinepubs/9699919799/functions/errno.html#tag_16_110_07
[1] §7.5, footnote 202 of ISO/IEC 9899:2011, WG14 draft version N1570
    (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)
[2] http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html#tag_16_590_04
@kamalmarhubi
Copy link
Contributor

Since the issue is that libc scope as defined in RFC 1291 doesn't include anything about errno, I opened rust-lang/rfcs#1571 to add it. Let's see where that goes.

@alexcrichton
Copy link
Member

Thanks @kamalmarhubi! I think that's the best next step here.

@pickfire
Copy link
Contributor

pickfire commented May 7, 2020

Is this still valid or can we move https://github.com/lambda-fairy/rust-errno here?

tgross35 pushed a commit to tgross35/rust-libc that referenced this issue Feb 22, 2025
tgross35 pushed a commit to tgross35/rust-libc that referenced this issue Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants