Solve stdin/out/err UB in a better way

This commit is contained in:
jD91mZM2
2018-07-25 14:29:14 +02:00
parent 992e50ef0f
commit e749d23030
10 changed files with 34 additions and 40 deletions
+13 -20
View File
@@ -1,37 +1,23 @@
use super::{constants, BUFSIZ, FILE, UNGET};
use core::cell::UnsafeCell;
use core::ptr;
use core::sync::atomic::AtomicBool;
struct GlobalFile(UnsafeCell<FILE>);
pub struct GlobalFile(UnsafeCell<FILE>);
impl GlobalFile {
const fn new(file: FILE) -> Self {
GlobalFile(UnsafeCell::new(file))
}
fn get(&self) -> *mut FILE {
pub fn get(&self) -> *mut FILE {
self.0.get()
}
}
// statics need to be Sync
unsafe impl Sync for GlobalFile {}
#[no_mangle]
pub extern "C" fn __stdin() -> *mut FILE {
default_stdin.get()
}
#[no_mangle]
pub extern "C" fn __stdout() -> *mut FILE {
default_stdout.get()
}
#[no_mangle]
pub extern "C" fn __stderr() -> *mut FILE {
default_stderr.get()
}
lazy_static! {
#[allow(non_upper_case_globals)]
static ref default_stdin: GlobalFile = GlobalFile::new(FILE {
pub static ref default_stdin: GlobalFile = GlobalFile::new(FILE {
flags: constants::F_PERM | constants::F_NOWR,
read: None,
write: None,
@@ -43,7 +29,7 @@ lazy_static! {
});
#[allow(non_upper_case_globals)]
static ref default_stdout: GlobalFile = GlobalFile::new(FILE {
pub static ref default_stdout: GlobalFile = GlobalFile::new(FILE {
flags: constants::F_PERM | constants::F_NORD,
read: None,
write: None,
@@ -55,7 +41,7 @@ lazy_static! {
});
#[allow(non_upper_case_globals)]
static ref default_stderr: GlobalFile = GlobalFile::new(FILE {
pub static ref default_stderr: GlobalFile = GlobalFile::new(FILE {
flags: constants::F_PERM | constants::F_NORD,
read: None,
write: None,
@@ -66,3 +52,10 @@ lazy_static! {
lock: AtomicBool::new(false),
});
}
#[no_mangle]
pub static mut stdin: *mut FILE = ptr::null_mut();
#[no_mangle]
pub static mut stdout: *mut FILE = ptr::null_mut();
#[no_mangle]
pub static mut stderr: *mut FILE = ptr::null_mut();
+8 -8
View File
@@ -643,7 +643,7 @@ pub extern "C" fn getc(stream: &mut FILE) -> c_int {
/// Get a single char from `stdin`
#[no_mangle]
pub extern "C" fn getchar() -> c_int {
fgetc(unsafe { &mut *__stdin() })
fgetc(unsafe { &mut *stdin })
}
/// Get a char from a stream without locking the stream
@@ -676,14 +676,14 @@ pub extern "C" fn getc_unlocked(stream: &mut FILE) -> c_int {
/// Get a char from `stdin` without locking `stdin`
#[no_mangle]
pub extern "C" fn getchar_unlocked() -> c_int {
getc_unlocked(unsafe { &mut *__stdin() })
getc_unlocked(unsafe { &mut *stdin })
}
/// Get a string from `stdin`
#[no_mangle]
pub extern "C" fn gets(s: *mut c_char) -> *mut c_char {
use core::i32;
fgets(s, i32::MAX, unsafe { &mut *__stdin() })
fgets(s, i32::MAX, unsafe { &mut *stdin })
}
/// Get an integer from `stream`
@@ -740,7 +740,7 @@ pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int {
/// Put a character `c` into `stdout`
#[no_mangle]
pub extern "C" fn putchar(c: c_int) -> c_int {
fputc(c, unsafe { &mut *__stdout() })
fputc(c, unsafe { &mut *stdout })
}
/// Put a character `c` into `stream` without locking `stream`
@@ -768,13 +768,13 @@ pub extern "C" fn putc_unlocked(c: c_int, stream: &mut FILE) -> c_int {
/// Put a character `c` into `stdout` without locking `stdout`
#[no_mangle]
pub extern "C" fn putchar_unlocked(c: c_int) -> c_int {
putc_unlocked(c, unsafe { &mut *__stdout() })
putc_unlocked(c, unsafe { &mut *stdout })
}
/// Put a string `s` into `stdout`
#[no_mangle]
pub extern "C" fn puts(s: *const c_char) -> c_int {
let ret = (fputs(s, unsafe { &mut *__stdout() }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
let ret = (fputs(s, unsafe { &mut *stdout }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
if ret {
0
} else {
@@ -918,7 +918,7 @@ pub unsafe extern "C" fn vfprintf(file: &mut FILE, format: *const c_char, ap: va
#[no_mangle]
pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
vfprintf(&mut *__stdout(), format, ap)
vfprintf(&mut *stdout, format, ap)
}
#[no_mangle]
@@ -947,7 +947,7 @@ pub unsafe extern "C" fn vfscanf(file: &mut FILE, format: *const c_char, ap: va_
#[no_mangle]
pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
vfscanf(&mut *__stdin(), format, ap)
vfscanf(&mut *stdin, format, ap)
}
#[no_mangle]