diff options
-rw-r--r-- | rustfmt.toml | 1 | ||||
-rw-r--r-- | safe_libc/src/boxed.rs | 150 | ||||
-rw-r--r-- | safe_libc/src/errno.rs | 7 | ||||
-rw-r--r-- | safe_libc/src/lib.rs | 7 | ||||
-rw-r--r-- | safe_libc/src/stdio.rs | 17 | ||||
-rw-r--r-- | safe_libc/src/string.rs | 72 | ||||
-rw-r--r-- | safe_libc/src/util.rs | 13 | ||||
-rw-r--r-- | src/main.rs | 17 | ||||
-rw-r--r-- | src/system_alloc.rs | 21 |
9 files changed, 73 insertions, 232 deletions
diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs deleted file mode 100644 index 4a38b70..0000000 --- a/safe_libc/src/boxed.rs +++ /dev/null @@ -1,150 +0,0 @@ -use crate::util; - -use core::{fmt, mem, ptr}; -use core::ops::{Deref, DerefMut}; - -fn alloc<T>(len: usize) -> *mut T { - if util::zst::<T>(len) { - return ptr::null_mut(); - } - let size = len.checked_mul(mem::size_of::<T>()).expect("allocation overflow"); - let align = mem::align_of::<T>(); - util::must_succeed( - unsafe { - libc::memalign(align, size) - } - ).cast() -} - -#[inline] -const fn dangling<T>() -> *mut T { - mem::align_of::<T>() as *mut T -} - -#[inline] -fn slice_len<T>(p: *const [T]) -> usize { - unsafe { mem::transmute::<_, [usize; 2]>(p)[1] } -} - -pub trait SafePtr { - fn safe_ptr(p: *mut Self) -> *mut Self; -} - -impl<T> SafePtr for T { - #[inline] - fn safe_ptr(p: *mut T) -> *mut T { - if util::zst::<T>(1) { - return dangling(); - } - - debug_assert!(!p.is_null(), "NULL ptr"); - p - } -} - -impl<T> SafePtr for [T] { - #[inline] - fn safe_ptr(p: *mut [T]) -> *mut [T] { - let len = slice_len(p); - if util::zst::<T>(len) { - return ptr::slice_from_raw_parts_mut(dangling(), len); - } - - debug_assert!(!p.is_null(), "NULL ptr"); - p - } -} - -pub struct CBox<T: SafePtr + ?Sized>(*mut T); - -impl<T: SafePtr + ?Sized> CBox<T> { - #[inline] - pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox<T> { - CBox(p) - } - - #[inline] - pub fn into_raw(self) -> *mut T { - let p = self.0; - mem::forget(self); - p - } - - #[inline] - pub fn as_ptr(&self) -> *const T { - self.0 - } - - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { - self.0 - } -} - -impl<T> CBox<T> { - #[inline] - pub fn new(value: T) -> CBox<T> { - let p = alloc(1); - unsafe { - ptr::write(p, value); - CBox::from_raw_unchecked(p) - } - } - - #[inline] - pub unsafe fn from_raw(p: *mut T) -> CBox<T> { - util::check_ptr(p, 1); - CBox(p) - } - - #[inline] - pub unsafe fn slice_from_raw_parts_unchecked(p: *mut T, len: usize) -> CBox<[T]> { - CBox(ptr::slice_from_raw_parts_mut(p, len)) - } - - #[inline] - pub unsafe fn slice_from_raw_parts(p: *mut T, len: usize) -> CBox<[T]> { - util::check_ptr(p, len); - CBox::slice_from_raw_parts_unchecked(p, len) - } -} - -impl<T: SafePtr + ?Sized> Drop for CBox<T> { - #[inline] - fn drop(&mut self) { - unsafe { - ptr::drop_in_place(self.0); - libc::free(self.0.cast()); - } - } -} - -impl<T: SafePtr + ?Sized> Deref for CBox<T> { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - unsafe { &*T::safe_ptr(self.0) } - } -} - -impl<T: SafePtr + ?Sized> DerefMut for CBox<T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *T::safe_ptr(self.0) } - } -} - -impl<T: fmt::Debug + SafePtr + ?Sized> fmt::Debug for CBox<T> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl<T: fmt::Display + SafePtr + ?Sized> fmt::Display for CBox<T> { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} diff --git a/safe_libc/src/errno.rs b/safe_libc/src/errno.rs index be944d1..2a2220b 100644 --- a/safe_libc/src/errno.rs +++ b/safe_libc/src/errno.rs @@ -6,9 +6,14 @@ use core::fmt; #[repr(transparent)] pub struct Errno(pub libc::c_int); +extern "C" { + //#[ffi_const] + pub fn __errno_location() -> *mut libc::c_int; +} + #[inline] pub fn errno() -> Errno { - unsafe { Errno(*libc::__errno_location()) } + unsafe { Errno(*__errno_location()) } } impl fmt::Display for Errno { diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs index aec5acc..6d9baf2 100644 --- a/safe_libc/src/lib.rs +++ b/safe_libc/src/lib.rs @@ -1,15 +1,18 @@ #![no_std] +#![feature(slice_ptr_len)] +#![feature(min_specialization)] +// #![feature(ffi_const)] + +extern crate alloc; pub use libc::*; mod util; -pub mod boxed; pub mod errno; pub mod stdio; pub mod string; - extern "C" { pub fn strndup(cs: *const libc::c_char, n: libc::size_t) -> *mut libc::c_char; diff --git a/safe_libc/src/stdio.rs b/safe_libc/src/stdio.rs index 2d19725..be016ab 100644 --- a/safe_libc/src/stdio.rs +++ b/safe_libc/src/stdio.rs @@ -41,28 +41,17 @@ pub fn stderr() -> Stderr { impl BasicOStream { #[inline] pub fn flush(&mut self) -> Result<()> { - check_io(unsafe { - libc::fflush(self.0) - } == 0) + check_io(unsafe { libc::fflush(self.0) } == 0) } #[inline] pub fn write(&mut self, b: &[u8]) -> Result<()> { - check_io(unsafe { - libc::fwrite( - b.as_ptr().cast(), - 1, - b.len(), - self.0, - ) - } == b.len()) + check_io(unsafe { libc::fwrite(b.as_ptr().cast(), 1, b.len(), self.0) } == b.len()) } #[inline] pub fn puts(&mut self, s: &string::CStr) -> Result<()> { - check_io(unsafe { - libc::fputs(s.as_ptr(), self.0) - } != libc::EOF) + check_io(unsafe { libc::fputs(s.as_ptr(), self.0) } != libc::EOF) } } diff --git a/safe_libc/src/string.rs b/safe_libc/src/string.rs index 53f8f87..6a8308a 100644 --- a/safe_libc/src/string.rs +++ b/safe_libc/src/string.rs @@ -1,39 +1,29 @@ -use crate::{self as libc, util, boxed::CBox}; +use crate::{self as libc, util}; -use core::slice; -use core::ops::{Deref, DerefMut}; +use alloc::boxed::Box; +use core::{ops::{Deref, DerefMut}, slice}; //pub struct FromBytesWithNulError {} #[repr(transparent)] -pub struct CStr { inner: libc::c_char } +pub struct CStr { + inner: libc::c_char, +} impl CStr { #[inline] - pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr { - &*p.cast() - } - - #[inline] pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr { - util::check_ptr(p, 1); - CStr::from_ptr_unchecked(p) - } - - #[inline] - pub unsafe fn from_mut_ptr_unchecked<'a>(p: *mut libc::c_char) -> &'a mut CStr { - &mut *p.cast() + &*p.cast() } #[inline] pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr { - util::check_ptr(p, 1); - CStr::from_mut_ptr_unchecked(p) + &mut *p.cast() } #[inline] pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { - CStr::from_ptr_unchecked(bytes.as_ptr().cast()) + CStr::from_ptr(bytes.as_ptr().cast()) } // TODO @@ -57,18 +47,12 @@ impl CStr { #[inline] pub fn to_bytes(&self) -> &[u8] { - unsafe { slice::from_raw_parts( - self.as_ptr().cast(), - self.len(), - ) } + unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len()) } } #[inline] pub fn to_mut_bytes(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut( - self.as_mut_ptr().cast(), - self.len(), - ) } + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) } } #[inline] @@ -89,28 +73,26 @@ impl CStr { #[macro_export] macro_rules! cstr { - ($s:expr) => ( + ($s:expr) => { unsafe { $crate::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) } - ) + }; } -pub struct CString { inner: CBox<libc::c_char> } +pub struct CString { + inner: Box<libc::c_char>, +} impl CString { #[inline] - pub unsafe fn from_raw_unchecked(p: *mut libc::c_char) -> CString { - CString { inner: CBox::from_raw_unchecked(p) } - } - - #[inline] pub unsafe fn from_raw(p: *mut libc::c_char) -> CString { - util::check_ptr(p, 1); - CString::from_raw_unchecked(p) + CString { + inner: Box::from_raw(p), + } } #[inline] pub fn into_raw(self) -> *mut libc::c_char { - self.inner.into_raw() + Box::into_raw(self.inner) } } @@ -133,12 +115,10 @@ impl DerefMut for CString { impl From<&[u8]> for CString { fn from(s: &[u8]) -> CString { unsafe { - CString::from_raw_unchecked( - util::must_succeed(libc::strndup( - s.as_ptr().cast(), - s.len(), - )) - ) + CString::from_raw(util::must_succeed(libc::strndup( + s.as_ptr().cast(), + s.len(), + ))) } } } @@ -153,8 +133,6 @@ impl From<&str> for CString { impl From<&CStr> for CString { #[inline] fn from(s: &CStr) -> CString { - unsafe { - CString::from_raw_unchecked(util::must_succeed(libc::strdup(s.as_ptr()))) - } + unsafe { CString::from_raw(util::must_succeed(libc::strdup(s.as_ptr()))) } } } diff --git a/safe_libc/src/util.rs b/safe_libc/src/util.rs index b8a4ed5..e91494e 100644 --- a/safe_libc/src/util.rs +++ b/safe_libc/src/util.rs @@ -1,16 +1,3 @@ -use core::mem; - -#[inline] -pub fn zst<T>(len: usize) -> bool { - mem::size_of::<T>() == 0 || len == 0 -} - -#[inline] -pub fn check_ptr<T>(p: *const T, len: usize) { - debug_assert!((p as usize) % mem::align_of::<T>() == 0, "unaligned ptr"); - assert!(zst::<T>(len) || !p.is_null(), "NULL ptr"); -} - #[inline] pub fn must_succeed<T>(p: *mut T) -> *mut T { assert!(!p.is_null(), "allocation failure"); diff --git a/src/main.rs b/src/main.rs index 26882ff..fe151fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ #![no_main] #![no_std] +#![feature(alloc_error_handler)] -use safe_libc as libc; +mod system_alloc; + +extern crate alloc; use libc::cstr; +use safe_libc as libc; use core::fmt::Write; @@ -19,17 +23,20 @@ pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) - let x = libc::string::CString::from("foo"); let l = x.len(); let y = x.into_raw(); - let z = unsafe { - libc::boxed::CBox::slice_from_raw_parts(y, l) - }; + let z = unsafe { alloc::boxed::Box::from_raw(core::ptr::slice_from_raw_parts_mut(y, l)) }; let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]); } { - let b = libc::boxed::CBox::new(42); + let b = alloc::boxed::Box::new(42); let _ = writeln!(stdout, "Bar: {}", b); } + { + let x = alloc::boxed::Box::new(()); + let _ = writeln!(stdout, "Box: {:?}", x); + } + 0 } diff --git a/src/system_alloc.rs b/src/system_alloc.rs new file mode 100644 index 0000000..ad1afcb --- /dev/null +++ b/src/system_alloc.rs @@ -0,0 +1,21 @@ +use safe_libc as libc; + +struct System; + +unsafe impl alloc::alloc::GlobalAlloc for System { + unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 { + libc::memalign(layout.align(), layout.size()).cast() + } + + unsafe fn dealloc(&self, ptr: *mut u8, _layout: alloc::alloc::Layout) { + libc::free(ptr.cast()); + } +} + +#[global_allocator] +static SYSTEM_ALLOC: System = System; + +#[alloc_error_handler] +fn alloc_error(_: core::alloc::Layout) -> ! { + panic!("allocation failure"); +} |