Merge branch 'err-unsafe' into 'master'
make unsafe usage explicit in err header See merge request redox-os/relibc!1416
This commit is contained in:
+70
-38
@@ -17,10 +17,6 @@
|
|||||||
//! and an error string for ERRNO. `errc` would operate in the same way except the functions takes
|
//! and an error string for ERRNO. `errc` would operate in the same way except the functions takes
|
||||||
//! an error code for which to print an error string.
|
//! an error code for which to print an error string.
|
||||||
|
|
||||||
// Allow is intentional. Almost every line of the simple functions below are unsafe.
|
|
||||||
// unsafe_op_in_unsafe_fn only adds visual noise or a needless indentation here.
|
|
||||||
#![allow(unsafe_op_in_unsafe_fn)]
|
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
ffi::{VaList as va_list, c_char, c_int},
|
ffi::{VaList as va_list, c_char, c_int},
|
||||||
ptr,
|
ptr,
|
||||||
@@ -46,16 +42,22 @@ static mut error_sink: *mut FILE = ptr::null_mut();
|
|||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn err_set_file(fp: *mut FILE) {
|
pub unsafe extern "C" fn err_set_file(fp: *mut FILE) {
|
||||||
if fp.is_null() {
|
if fp.is_null() {
|
||||||
error_sink = stdio::stderr;
|
unsafe {
|
||||||
|
error_sink = stdio::stderr;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error_sink = fp;
|
unsafe {
|
||||||
|
error_sink = fp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set or remove a callback to invoke before exiting on error.
|
/// Set or remove a callback to invoke before exiting on error.
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn err_set_exit(ef: ExitCallback) {
|
pub unsafe extern "C" fn err_set_exit(ef: ExitCallback) {
|
||||||
on_exit = ef;
|
unsafe {
|
||||||
|
on_exit = ef;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a user message then an error message for [`ERRNO`] followed by exiting with `eval`.
|
/// Print a user message then an error message for [`ERRNO`] followed by exiting with `eval`.
|
||||||
@@ -67,7 +69,7 @@ pub unsafe extern "C" fn err_set_exit(ef: ExitCallback) {
|
|||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn err(eval: c_int, fmt: *const c_char, va_list: ...) -> ! {
|
pub unsafe extern "C" fn err(eval: c_int, fmt: *const c_char, va_list: ...) -> ! {
|
||||||
let code = Some(ERRNO.get());
|
let code = Some(ERRNO.get());
|
||||||
err_exit(eval, code, fmt, va_list)
|
unsafe { err_exit(eval, code, fmt, va_list) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a user message then an error message for `code` before exiting with `eval` as a return.
|
/// Print a user message then an error message for `code` before exiting with `eval` as a return.
|
||||||
@@ -78,7 +80,7 @@ pub unsafe extern "C" fn err(eval: c_int, fmt: *const c_char, va_list: ...) -> !
|
|||||||
/// Exits with `eval` as an error code.
|
/// Exits with `eval` as an error code.
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn errc(eval: c_int, code: c_int, fmt: *const c_char, va_list: ...) -> ! {
|
pub unsafe extern "C" fn errc(eval: c_int, code: c_int, fmt: *const c_char, va_list: ...) -> ! {
|
||||||
err_exit(eval, Some(code), fmt, va_list)
|
unsafe { err_exit(eval, Some(code), fmt, va_list) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a user message then exits with `eval` as a return.
|
/// Print a user message then exits with `eval` as a return.
|
||||||
@@ -89,7 +91,7 @@ pub unsafe extern "C" fn errc(eval: c_int, code: c_int, fmt: *const c_char, va_l
|
|||||||
/// Exits with `eval` as an error code.
|
/// Exits with `eval` as an error code.
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn errx(eval: c_int, fmt: *const c_char, va_list: ...) -> ! {
|
pub unsafe extern "C" fn errx(eval: c_int, fmt: *const c_char, va_list: ...) -> ! {
|
||||||
err_exit(eval, None, fmt, va_list)
|
unsafe { err_exit(eval, None, fmt, va_list) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a user message and then an error message for [`ERRNO`].
|
/// Print a user message and then an error message for [`ERRNO`].
|
||||||
@@ -98,7 +100,9 @@ pub unsafe extern "C" fn errx(eval: c_int, fmt: *const c_char, va_list: ...) ->
|
|||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn warn(fmt: *const c_char, va_list: ...) {
|
pub unsafe extern "C" fn warn(fmt: *const c_char, va_list: ...) {
|
||||||
let code = Some(ERRNO.get());
|
let code = Some(ERRNO.get());
|
||||||
display_message(code, fmt, va_list);
|
unsafe {
|
||||||
|
display_message(code, fmt, va_list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a user message then an error message for `code`.
|
/// Print a user message then an error message for `code`.
|
||||||
@@ -106,7 +110,9 @@ pub unsafe extern "C" fn warn(fmt: *const c_char, va_list: ...) {
|
|||||||
/// The message format is `progname: fmt: strerror(code)`
|
/// The message format is `progname: fmt: strerror(code)`
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn warnc(code: c_int, fmt: *const c_char, va_list: ...) {
|
pub unsafe extern "C" fn warnc(code: c_int, fmt: *const c_char, va_list: ...) {
|
||||||
display_message(Some(code), fmt, va_list);
|
unsafe {
|
||||||
|
display_message(Some(code), fmt, va_list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a user message as a warning.
|
/// Print a user message as a warning.
|
||||||
@@ -114,45 +120,55 @@ pub unsafe extern "C" fn warnc(code: c_int, fmt: *const c_char, va_list: ...) {
|
|||||||
/// The message format is `progname: fmt`
|
/// The message format is `progname: fmt`
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn warnx(fmt: *const c_char, va_list: ...) {
|
pub unsafe extern "C" fn warnx(fmt: *const c_char, va_list: ...) {
|
||||||
display_message(None, fmt, va_list);
|
unsafe {
|
||||||
|
display_message(None, fmt, va_list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`err`].
|
/// See [`err`].
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn verr(eval: c_int, fmt: *const c_char, args: va_list) -> ! {
|
pub unsafe extern "C" fn verr(eval: c_int, fmt: *const c_char, args: va_list) -> ! {
|
||||||
let code = Some(ERRNO.get());
|
let code = Some(ERRNO.get());
|
||||||
err_exit(eval, code, fmt, args);
|
unsafe {
|
||||||
|
err_exit(eval, code, fmt, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`errc`].
|
/// See [`errc`].
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn verrc(eval: c_int, code: c_int, fmt: *const c_char, args: va_list) -> ! {
|
pub unsafe extern "C" fn verrc(eval: c_int, code: c_int, fmt: *const c_char, args: va_list) -> ! {
|
||||||
err_exit(eval, Some(code), fmt, args)
|
unsafe { err_exit(eval, Some(code), fmt, args) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`errx`];
|
/// See [`errx`];
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn verrx(eval: c_int, fmt: *const c_char, args: va_list) -> ! {
|
pub unsafe extern "C" fn verrx(eval: c_int, fmt: *const c_char, args: va_list) -> ! {
|
||||||
err_exit(eval, None, fmt, args)
|
unsafe { err_exit(eval, None, fmt, args) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`warn`].
|
/// See [`warn`].
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn vwarn(fmt: *const c_char, args: va_list) {
|
pub unsafe extern "C" fn vwarn(fmt: *const c_char, args: va_list) {
|
||||||
let code = Some(ERRNO.get());
|
let code = Some(ERRNO.get());
|
||||||
display_message(code, fmt, args);
|
unsafe {
|
||||||
|
display_message(code, fmt, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`warnc`].
|
/// See [`warnc`].
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn vwarnc(code: c_int, fmt: *const c_char, args: va_list) {
|
pub unsafe extern "C" fn vwarnc(code: c_int, fmt: *const c_char, args: va_list) {
|
||||||
display_message(Some(code), fmt, args);
|
unsafe {
|
||||||
|
display_message(Some(code), fmt, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`warnx`].
|
/// See [`warnx`].
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub unsafe extern "C" fn vwarnx(fmt: *const c_char, args: va_list) {
|
pub unsafe extern "C" fn vwarnx(fmt: *const c_char, args: va_list) {
|
||||||
display_message(None, fmt, args);
|
unsafe {
|
||||||
|
display_message(None, fmt, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write error messages for err and warn to the currently set sink.
|
// Write error messages for err and warn to the currently set sink.
|
||||||
@@ -160,45 +176,61 @@ unsafe fn display_message(code: Option<c_int>, fmt: *const c_char, args: va_list
|
|||||||
// SAFETY:
|
// SAFETY:
|
||||||
// * error_sink is only null once on start but otherwise always stderr or a user set file
|
// * error_sink is only null once on start but otherwise always stderr or a user set file
|
||||||
// * User is trusted to pass in a valid file pointer if err_set_file is used
|
// * User is trusted to pass in a valid file pointer if err_set_file is used
|
||||||
if error_sink.is_null() {
|
if unsafe { error_sink.is_null() } {
|
||||||
error_sink = stdio::stderr;
|
unsafe {
|
||||||
|
error_sink = stdio::stderr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let sink = error_sink;
|
let sink = unsafe { error_sink };
|
||||||
|
|
||||||
// "progname:" is always printed
|
// "progname:" is always printed
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// * program_invocation_short_name is never null as it is set on start
|
// * program_invocation_short_name is never null as it is set on start
|
||||||
// * program_invocation_short_name is not globally mutable so the user can't mangle it
|
// * program_invocation_short_name is not globally mutable so the user can't mangle it
|
||||||
fprintf(
|
unsafe {
|
||||||
sink,
|
fprintf(
|
||||||
c"%s".as_ptr(),
|
sink,
|
||||||
platform::program_invocation_short_name,
|
c"%s".as_ptr(),
|
||||||
);
|
platform::program_invocation_short_name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Print user message if any
|
// Print user message if any
|
||||||
if !fmt.is_null() {
|
if !fmt.is_null() {
|
||||||
fputs(c": ".as_ptr(), sink);
|
unsafe {
|
||||||
vfprintf(sink, fmt, args);
|
fputs(c": ".as_ptr(), sink);
|
||||||
|
vfprintf(sink, fmt, args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print error message for non-x functions
|
// Print error message for non-x functions
|
||||||
if let Some(code) = code {
|
if let Some(code) = code {
|
||||||
let message = strerror(code);
|
unsafe {
|
||||||
fprintf(sink, c": %s".as_ptr(), message);
|
let message = strerror(code);
|
||||||
|
fprintf(sink, c": %s".as_ptr(), message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always write new line
|
// Always write new line
|
||||||
fputc(b'\n'.into(), sink);
|
unsafe {
|
||||||
|
fputc(b'\n'.into(), sink);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write an error message as per err and then exit.
|
// Write an error message as per err and then exit.
|
||||||
unsafe fn err_exit(eval: c_int, code: Option<c_int>, fmt: *const c_char, args: va_list) -> ! {
|
unsafe fn err_exit(eval: c_int, code: Option<c_int>, fmt: *const c_char, args: va_list) -> ! {
|
||||||
display_message(code, fmt, args);
|
unsafe {
|
||||||
|
display_message(code, fmt, args);
|
||||||
if let Some(callback) = on_exit {
|
|
||||||
// errx will hit the unwrap.
|
|
||||||
callback(code.unwrap_or_else(|| ERRNO.get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(eval);
|
if let Some(callback) = unsafe { on_exit } {
|
||||||
|
// errx will hit the unwrap.
|
||||||
|
unsafe {
|
||||||
|
callback(code.unwrap_or_else(|| ERRNO.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
exit(eval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user