Skip to content

Add libc::errno and libc::set_errno and use to implement std::os::errno #18642

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
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions src/liblibc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ pub use consts::os::extra::{IPPROTO_RAW};
pub use funcs::c95::ctype::{isalnum, isalpha, iscntrl, isdigit};
pub use funcs::c95::ctype::{islower, isprint, ispunct, isspace};
pub use funcs::c95::ctype::{isupper, isxdigit, tolower, toupper};
pub use funcs::c95::errno::{errno, set_errno};

pub use funcs::c95::stdio::{fclose, feof, ferror, fflush, fgetc};
pub use funcs::c95::stdio::{fgetpos, fgets, fopen, fputc, fputs};
Expand Down Expand Up @@ -3986,6 +3987,9 @@ pub mod funcs {
// Thankfully most of c95 is universally available and does not vary by OS
// or anything. The same is not true of POSIX.

// The interface to errno is OS dependent however, with the Windows implementation
// using GetLastError rather than the errno provided by CRT.

pub mod c95 {
pub mod ctype {
use types::os::arch::c95::{c_char, c_int};
Expand All @@ -4007,6 +4011,91 @@ pub mod funcs {
}
}

#[cfg(unix)]
pub mod errno {
use types::os::arch::c95::{c_int};

/// Return a pointer to the platform-specific value of errno
fn errno_ptr() -> *mut c_int {
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd"))]
fn _errno_ptr() -> *mut c_int {
extern {
fn __error() -> *mut c_int;
}
unsafe {
__error()
}
}

#[cfg(target_os = "dragonfly")]
fn _errno_ptr() -> *mut c_int {
extern {
fn __dfly_error() -> *mut c_int;
}
unsafe {
__dfly_error()
}
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn _errno_ptr() -> *mut c_int {
extern {
fn __errno_location() -> *mut c_int;
}
unsafe {
__errno_location()
}
}

_errno_ptr()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what was the benefit of defining errno_ptr() on top of _errno_ptr() which can hide platform-dependency by themselves.

Incidentally, ::{c_int} isn't beautiful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question of whether use <...>::{c_int} is not beautiful is probably a debatable one :-). In either case, the style has been chosen as it matches all of the other single name use ... statements within this source file.

As to defining errno_ptr() over _errno_ptr(). I guess the benefits are that it ensures errno_ptr is implemented on all target_os possibilities. If a value of target_os is not covered by the _errno_ptr implementations, the function errno_ptr won't compile, providing a hint that it needs to be implemented for that new platform. (granted, if it wasn't done this way, errno and set_errno wouldn't compile, but that is a slightly less specific error)

It also means the function only needs to be documented at this single entrypoint.

But again, the implementation was mostly influenced by what the existing errno source had been doing.

}

/// Returns the platform-specific value of errno
pub fn errno() -> c_int {
unsafe {
*errno_ptr()
}
}

/// Set the platform-specific value of errno
pub fn set_errno(e: c_int) {
unsafe {
*errno_ptr() = e
}
}
}

#[cfg(windows)]
pub mod errno {
use types::os::arch::extra::DWORD;

/// Returns the platform-specific value of errno
pub fn errno() -> DWORD {
#[link_name = "kernel32"]
extern "system" {
fn GetLastError() -> DWORD;
}

unsafe {
GetLastError()
}
}

/// Set the platform-specific value of errno
pub fn set_errno(e: DWORD) {
#[link_name = "kernel32"]
extern "system" {
fn SetLastError(dwErrCode: DWORD);
}

unsafe {
SetLastError(e)
}
}
}

pub mod stdio {
use types::common::c95::{FILE, c_void, fpos_t};
use types::os::arch::c95::{c_char, c_int, c_long, size_t};
Expand Down
70 changes: 19 additions & 51 deletions src/libstd/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,59 +905,9 @@ pub fn change_dir(p: &Path) -> bool {
}
}

#[cfg(unix)]
/// Returns the platform-specific value of errno
pub fn errno() -> int {
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd"))]
fn errno_location() -> *const c_int {
extern {
fn __error() -> *const c_int;
}
unsafe {
__error()
}
}

#[cfg(target_os = "dragonfly")]
fn errno_location() -> *const c_int {
extern {
fn __dfly_error() -> *const c_int;
}
unsafe {
__dfly_error()
}
}

#[cfg(any(target_os = "linux", target_os = "android"))]
fn errno_location() -> *const c_int {
extern {
fn __errno_location() -> *const c_int;
}
unsafe {
__errno_location()
}
}

unsafe {
(*errno_location()) as int
}
}

#[cfg(windows)]
/// Returns the platform-specific value of errno
pub fn errno() -> uint {
use libc::types::os::arch::extra::DWORD;

#[link_name = "kernel32"]
extern "system" {
fn GetLastError() -> DWORD;
}

unsafe {
GetLastError() as uint
}
libc::errno() as int
}

/// Return the string corresponding to an `errno()` value of `errnum`.
Expand Down Expand Up @@ -2043,6 +1993,24 @@ mod tests {
assert!(e.contains(&(n, "VALUE".to_string())));
}

#[test]
#[cfg(unix)]
fn test_errno() {
os::set_errno(100);
assert!(os::errno() == 100);
os::set_errno(0);
assert!(os::errno() == 0);
}

#[test]
#[cfg(windows)]
fn test_errno() {
os::set_errno(100);
assert!(os::errno() == 100);
os::set_errno(0);
assert!(os::errno() == 0);
}

#[test]
fn test() {
assert!((!Path::new("test-path").is_absolute()));
Expand Down