Hi folks!
The __errno_location
exposed by libc returns a raw pointer to the calling thread's last error code. Let's say I'm trying to create a safe wrapper for that function.
type Errno = i32;
extern "C" {
fn __errno_location() -> *mut Errno;
}
fn get_last_error() -> Errno {
// SAFETY:
// The only way to safely access the referenced errno is to use either
// `get_last_error` or `set_last_error`, ensuring that no one currently
// holds a mutable reference to the underlying value.
unsafe { *libc::__errno_location() }
}
fn set_last_error(code: Errno) {
// SAFETY:
// The only way to safely access the referenced errno is to use either
// `set_last_error` or `get_last_error`, ensuring that no one currently
// holds any reference to the underlying value.
unsafe { *libc::__errno_location() = code };
}
But this pattern reminds me a lot of what Cell<T>
do. They either copy the value, or modify it without giving out references. And Cell<T>
needs an UnsafeCell<T>
. Is the above code sound? It seems to emulate a Cell<T>
, but does not seem to need an UnsafeCell<T>
.
Would something like that be more correct?
fn get_errno_cell() -> &'static Cell<Errno> {
// SAFETY:
// The `get_errno_cell` function is the only safe way to access the
// underlying value, ensuring that the implied `Cell<T>` "logically
// owns" the referenced value.
unsafe { &*(libc::__errno_location() as *const Cell<Errno>) }
}
fn get_last_error() -> Errno {
get_errno_cell().get()
}
fn set_last_error(err: Errno) {
get_errno_cell().set(err);
}