From 5b449f4e1e43bc59109da5a37edf5ec911d3df8e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 13 Apr 2020 02:13:58 +0200 Subject: [PATCH 01/10] IO, error handling --- safe_libc/src/boxed.rs | 2 +- safe_libc/src/errno.rs | 29 +++++++++++ safe_libc/src/lib.rs | 1 + safe_libc/src/stdio.rs | 110 +++++++++++++++++++++++++++++++--------- safe_libc/src/string.rs | 23 ++++++--- src/main.rs | 7 +-- 6 files changed, 138 insertions(+), 34 deletions(-) create mode 100644 safe_libc/src/errno.rs diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs index fa3e45d..4a38b70 100644 --- a/safe_libc/src/boxed.rs +++ b/safe_libc/src/boxed.rs @@ -11,7 +11,7 @@ fn alloc(len: usize) -> *mut T { let align = mem::align_of::(); util::must_succeed( unsafe { - libc::memalign(align as libc::size_t, size as libc::size_t) + libc::memalign(align, size) } ).cast() } diff --git a/safe_libc/src/errno.rs b/safe_libc/src/errno.rs new file mode 100644 index 0000000..be944d1 --- /dev/null +++ b/safe_libc/src/errno.rs @@ -0,0 +1,29 @@ +use crate::string; + +use core::fmt; + +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct Errno(pub libc::c_int); + +#[inline] +pub fn errno() -> Errno { + unsafe { Errno(*libc::__errno_location()) } +} + +impl fmt::Display for Errno { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut buf = [0u8; 1024]; + let cstr = unsafe { + if libc::strerror_r(self.0, buf.as_mut_ptr().cast(), buf.len()) != 0 { + return Err(fmt::Error); + } + string::CStr::from_bytes_with_nul_unchecked(&buf) + }; + match cstr.to_str() { + Err(_) => Err(fmt::Error), + Ok(s) => f.write_str(s), + } + } +} diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs index 0ab0e89..aec5acc 100644 --- a/safe_libc/src/lib.rs +++ b/safe_libc/src/lib.rs @@ -5,6 +5,7 @@ pub use libc::*; mod util; pub mod boxed; +pub mod errno; pub mod stdio; pub mod string; diff --git a/safe_libc/src/stdio.rs b/safe_libc/src/stdio.rs index 271f023..2d19725 100644 --- a/safe_libc/src/stdio.rs +++ b/safe_libc/src/stdio.rs @@ -1,47 +1,111 @@ -use crate as libc; -use crate::string; +use crate::{self as libc, errno, string}; use core::fmt; +use core::ops::{Deref, DerefMut}; -pub struct OStream { - file: *mut libc::FILE +pub struct Error { + pub errno: errno::Errno, +} + +pub type Result = core::result::Result; + +#[inline] +fn check_io(ok: bool) -> Result<()> { + if ok { + Ok(()) + } else { + Err(Error { + errno: errno::errno(), + }) + } +} + +pub struct BasicOStream(*mut libc::FILE); + +unsafe impl Sync for BasicOStream {} +unsafe impl Send for BasicOStream {} + +pub type Stdout = BasicOStream; +pub type Stderr = BasicOStream; + +#[inline] +pub fn stdout() -> Stdout { + BasicOStream(unsafe { libc::stdout }) } #[inline] -pub unsafe fn stdout() -> OStream { - OStream { file: libc::stdout } +pub fn stderr() -> Stderr { + BasicOStream(unsafe { libc::stderr }) } -#[inline] -pub unsafe fn stderr() -> OStream { - OStream { file: libc::stderr } -} - -impl OStream { +impl BasicOStream { #[inline] - pub fn write(&mut self, b: &[u8]) { - unsafe { + pub fn flush(&mut self) -> Result<()> { + 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.file, - ); - } + self.0, + ) + } == b.len()) } #[inline] - pub fn puts(&mut self, s: &string::CStr) { - unsafe { - libc::fputs(s.as_ptr(), self.file); - } + pub fn puts(&mut self, s: &string::CStr) -> Result<()> { + check_io(unsafe { + libc::fputs(s.as_ptr(), self.0) + } != libc::EOF) } } -impl fmt::Write for OStream { +impl fmt::Write for BasicOStream { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { - self.write(s.as_bytes()); + if self.write(s.as_bytes()).is_err() { + return Err(fmt::Error); + } Ok(()) } } + +pub struct OStream(BasicOStream); + +impl OStream { + #[inline] + pub unsafe fn from_raw(file: *mut libc::FILE) -> OStream { + OStream(BasicOStream(file)) + } +} + +impl Drop for OStream { + #[inline] + fn drop(&mut self) { + unsafe { + libc::fclose((self.0).0); + } + } +} + +impl Deref for OStream { + type Target = BasicOStream; + + #[inline] + fn deref(&self) -> &BasicOStream { + &self.0 + } +} + +impl DerefMut for OStream { + #[inline] + fn deref_mut(&mut self) -> &mut BasicOStream { + &mut self.0 + } +} diff --git a/safe_libc/src/string.rs b/safe_libc/src/string.rs index 8f973ad..53f8f87 100644 --- a/safe_libc/src/string.rs +++ b/safe_libc/src/string.rs @@ -1,12 +1,11 @@ -use crate as libc; -use crate::util; -use crate::boxed::CBox; +use crate::{self as libc, util, boxed::CBox}; use core::slice; use core::ops::{Deref, DerefMut}; //pub struct FromBytesWithNulError {} +#[repr(transparent)] pub struct CStr { inner: libc::c_char } impl CStr { @@ -43,7 +42,7 @@ impl CStr { #[inline] pub fn len(&self) -> usize { - unsafe { libc::strlen(self.as_ptr()) as usize } + unsafe { libc::strlen(self.as_ptr()) } } #[inline] @@ -57,7 +56,7 @@ impl CStr { } #[inline] - pub fn as_bytes(&self) -> &[u8] { + pub fn to_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts( self.as_ptr().cast(), self.len(), @@ -65,13 +64,23 @@ impl CStr { } #[inline] - pub fn as_mut_bytes(&mut self) -> &mut [u8] { + pub fn to_mut_bytes(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut( self.as_mut_ptr().cast(), self.len(), ) } } + #[inline] + pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { + core::str::from_utf8(self.to_bytes()) + } + + #[inline] + pub fn to_mut_str(&mut self) -> Result<&mut str, core::str::Utf8Error> { + core::str::from_utf8_mut(self.to_mut_bytes()) + } + #[inline] pub fn to_owned(self: &CStr) -> CString { CString::from(self) @@ -127,7 +136,7 @@ impl From<&[u8]> for CString { CString::from_raw_unchecked( util::must_succeed(libc::strndup( s.as_ptr().cast(), - s.len() as libc::size_t, + s.len(), )) ) } diff --git a/src/main.rs b/src/main.rs index c79f1da..26882ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,11 +8,11 @@ use core::fmt::Write; #[no_mangle] pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int { - let mut stdout = unsafe { libc::stdio::stdout() }; + let mut stdout = libc::stdio::stdout(); { let foo = cstr!("Foo!\n"); - stdout.puts(foo); + let _ = stdout.puts(foo); } { @@ -29,11 +29,12 @@ pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) - let b = libc::boxed::CBox::new(42); let _ = writeln!(stdout, "Bar: {}", b); } + 0 } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - let _ = writeln!(unsafe { libc::stdio::stderr() }, "Panic: {}", info); + let _ = writeln!(libc::stdio::stderr(), "Panic: {}", info); unsafe { libc::abort() } } From fd2384b7fab14732efde99da8affd830e2334e16 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 1 May 2020 18:46:23 +0200 Subject: [PATCH 02/10] Nightly stuff --- rustfmt.toml | 1 + safe_libc/src/boxed.rs | 150 ---------------------------------------- safe_libc/src/errno.rs | 7 +- safe_libc/src/lib.rs | 7 +- safe_libc/src/stdio.rs | 17 +---- safe_libc/src/string.rs | 72 +++++++------------ safe_libc/src/util.rs | 13 ---- src/main.rs | 17 +++-- src/system_alloc.rs | 21 ++++++ 9 files changed, 73 insertions(+), 232 deletions(-) create mode 100644 rustfmt.toml delete mode 100644 safe_libc/src/boxed.rs create mode 100644 src/system_alloc.rs 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(len: usize) -> *mut T { - if util::zst::(len) { - return ptr::null_mut(); - } - let size = len.checked_mul(mem::size_of::()).expect("allocation overflow"); - let align = mem::align_of::(); - util::must_succeed( - unsafe { - libc::memalign(align, size) - } - ).cast() -} - -#[inline] -const fn dangling() -> *mut T { - mem::align_of::() as *mut T -} - -#[inline] -fn slice_len(p: *const [T]) -> usize { - unsafe { mem::transmute::<_, [usize; 2]>(p)[1] } -} - -pub trait SafePtr { - fn safe_ptr(p: *mut Self) -> *mut Self; -} - -impl SafePtr for T { - #[inline] - fn safe_ptr(p: *mut T) -> *mut T { - if util::zst::(1) { - return dangling(); - } - - debug_assert!(!p.is_null(), "NULL ptr"); - p - } -} - -impl SafePtr for [T] { - #[inline] - fn safe_ptr(p: *mut [T]) -> *mut [T] { - let len = slice_len(p); - if util::zst::(len) { - return ptr::slice_from_raw_parts_mut(dangling(), len); - } - - debug_assert!(!p.is_null(), "NULL ptr"); - p - } -} - -pub struct CBox(*mut T); - -impl CBox { - #[inline] - pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox { - 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 CBox { - #[inline] - pub fn new(value: T) -> CBox { - let p = alloc(1); - unsafe { - ptr::write(p, value); - CBox::from_raw_unchecked(p) - } - } - - #[inline] - pub unsafe fn from_raw(p: *mut T) -> CBox { - 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 Drop for CBox { - #[inline] - fn drop(&mut self) { - unsafe { - ptr::drop_in_place(self.0); - libc::free(self.0.cast()); - } - } -} - -impl Deref for CBox { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - unsafe { &*T::safe_ptr(self.0) } - } -} - -impl DerefMut for CBox { - #[inline] - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *T::safe_ptr(self.0) } - } -} - -impl fmt::Debug for CBox { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl fmt::Display for CBox { - #[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 { + pub unsafe fn from_ptr<'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 { + pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr { &mut *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) - } - #[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 } +pub struct CString { + inner: Box, +} 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(len: usize) -> bool { - mem::size_of::() == 0 || len == 0 -} - -#[inline] -pub fn check_ptr(p: *const T, len: usize) { - debug_assert!((p as usize) % mem::align_of::() == 0, "unaligned ptr"); - assert!(zst::(len) || !p.is_null(), "NULL ptr"); -} - #[inline] pub fn must_succeed(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"); +} From a205bbb1d286d78efbb325dac1d465c6908e0026 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 1 May 2020 22:21:17 +0200 Subject: [PATCH 03/10] Use extern type for CStr --- safe_libc/src/boxed.rs | 78 +++++++++++++++++++++++++++++++++++++++++ safe_libc/src/lib.rs | 3 +- safe_libc/src/string.rs | 36 ++++++++++--------- src/main.rs | 5 +++ 4 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 safe_libc/src/boxed.rs diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs new file mode 100644 index 0000000..a0bbfb4 --- /dev/null +++ b/safe_libc/src/boxed.rs @@ -0,0 +1,78 @@ +use core::{marker, mem, ptr}; +use core::ops::{Deref, DerefMut}; + +pub trait Dealloc { + unsafe fn dealloc(p: *mut T); +} + +#[repr(transparent)] +pub struct BoxLike> { + inner: ptr::NonNull, + _phantom: marker::PhantomData, + _dropper: marker::PhantomData, +} + +impl> BoxLike { + #[inline] + pub unsafe fn from_raw_unchecked(p: *mut T) -> Self { + BoxLike { + inner: ptr::NonNull::new_unchecked(p), + _phantom: marker::PhantomData, + _dropper: marker::PhantomData, + } + } + + #[inline] + pub unsafe fn from_raw(p: *mut T) -> Option { + if p.is_null() { + None + } else { + Some(Self::from_raw_unchecked(p)) + } + } + + #[inline] + pub fn into_raw(self) -> *mut T { + let p = self.inner.as_ptr(); + mem::forget(self); + p + } +} + +impl> Drop for BoxLike { + #[inline] + fn drop(&mut self) { + let p = self.inner.as_ptr(); + unsafe { + ptr::drop_in_place(p); + D::dealloc(p); + } + } +} + +impl> Deref for BoxLike { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { self.inner.as_ref() } + } +} + +impl> DerefMut for BoxLike { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { self.inner.as_mut() } + } +} + +pub struct DeallocFree; + +impl Dealloc for DeallocFree { + #[inline] + unsafe fn dealloc(p: *mut T) { + libc::free(p as _); + } +} + +pub type CBox = BoxLike; diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs index 6d9baf2..2e39b8d 100644 --- a/safe_libc/src/lib.rs +++ b/safe_libc/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] +#![feature(extern_types)] #![feature(slice_ptr_len)] -#![feature(min_specialization)] // #![feature(ffi_const)] extern crate alloc; @@ -9,6 +9,7 @@ pub use libc::*; mod util; +pub mod boxed; pub mod errno; pub mod stdio; pub mod string; diff --git a/safe_libc/src/string.rs b/safe_libc/src/string.rs index 6a8308a..5483e08 100644 --- a/safe_libc/src/string.rs +++ b/safe_libc/src/string.rs @@ -1,24 +1,26 @@ -use crate::{self as libc, util}; +use crate::{self as libc, boxed::CBox, util}; -use alloc::boxed::Box; -use core::{ops::{Deref, DerefMut}, slice}; +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; //pub struct FromBytesWithNulError {} -#[repr(transparent)] -pub struct CStr { - inner: libc::c_char, +extern "C" { + type RawCStr; } +#[repr(transparent)] +pub struct CStr(RawCStr); + impl CStr { #[inline] pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr { - &*p.cast() + &*(p as *const CStr) } #[inline] pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr { - &mut *p.cast() + &mut *(p as *mut CStr) } #[inline] @@ -37,12 +39,12 @@ impl CStr { #[inline] pub const fn as_ptr(&self) -> *const libc::c_char { - &self.inner + (self as *const CStr).cast() } #[inline] pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { - &mut self.inner + (self as *mut CStr).cast() } #[inline] @@ -79,20 +81,22 @@ macro_rules! cstr { } pub struct CString { - inner: Box, + inner: CBox, } impl CString { #[inline] pub unsafe fn from_raw(p: *mut libc::c_char) -> CString { CString { - inner: Box::from_raw(p), + inner: CBox::from_raw_unchecked(p as *mut CStr) } } #[inline] - pub fn into_raw(self) -> *mut libc::c_char { - Box::into_raw(self.inner) + pub fn into_raw(mut self) -> *mut libc::c_char { + let p = self.as_mut_ptr(); + mem::forget(self); + p } } @@ -101,14 +105,14 @@ impl Deref for CString { #[inline] fn deref(&self) -> &CStr { - unsafe { CStr::from_ptr(&*self.inner) } + &*self.inner } } impl DerefMut for CString { #[inline] fn deref_mut(&mut self) -> &mut CStr { - unsafe { CStr::from_mut_ptr(&mut *self.inner) } + &mut *self.inner } } diff --git a/src/main.rs b/src/main.rs index fe151fe..c6ec961 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,11 @@ pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) - let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]); } + { + let x = libc::string::CString::from("bar"); + let _ = stdout.puts(&x); + } + { let b = alloc::boxed::Box::new(42); let _ = writeln!(stdout, "Bar: {}", b); From 4f5b90400e414e77f067b8831e3296ce569352ed Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 1 May 2020 23:57:16 +0200 Subject: [PATCH 04/10] util: use handle_alloc_error() --- safe_libc/src/util.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/safe_libc/src/util.rs b/safe_libc/src/util.rs index e91494e..d37954c 100644 --- a/safe_libc/src/util.rs +++ b/safe_libc/src/util.rs @@ -1,5 +1,9 @@ +use alloc::alloc; + #[inline] pub fn must_succeed(p: *mut T) -> *mut T { - assert!(!p.is_null(), "allocation failure"); + if p.is_null() { + alloc::handle_alloc_error(alloc::Layout::new::()) + } p } From acafb83a63b4f99b3340b84d8e1ea3ba267bd80a Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 1 May 2020 23:58:57 +0200 Subject: [PATCH 05/10] Update libc --- Cargo.lock | 4 ++-- safe_libc/Cargo.lock | 4 ++-- safe_libc/Cargo.toml | 2 +- safe_libc/src/lib.rs | 2 -- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45e6ba1..81b8dd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "libc" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" [[package]] name = "neco" diff --git a/safe_libc/Cargo.lock b/safe_libc/Cargo.lock index e659af2..b20b067 100644 --- a/safe_libc/Cargo.lock +++ b/safe_libc/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "libc" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" [[package]] name = "safe_libc" diff --git a/safe_libc/Cargo.toml b/safe_libc/Cargo.toml index f776d09..3741877 100644 --- a/safe_libc/Cargo.toml +++ b/safe_libc/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = { version = "0.2.68", default-features = false } +libc = { version = "0.2.69", default-features = false } diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs index 2e39b8d..9356406 100644 --- a/safe_libc/src/lib.rs +++ b/safe_libc/src/lib.rs @@ -15,8 +15,6 @@ pub mod stdio; pub mod string; extern "C" { - pub fn strndup(cs: *const libc::c_char, n: libc::size_t) -> *mut libc::c_char; - // pub static stdin: *mut libc::FILE; pub static stdout: *mut libc::FILE; pub static stderr: *mut libc::FILE; From 85d52f3db69126ad9d374f03e32c22fded058570 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 19 May 2020 00:54:23 +0200 Subject: [PATCH 06/10] Fix --all-targets build --- src/main.rs | 1 + src/system_alloc.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main.rs b/src/main.rs index c6ec961..4283396 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,7 @@ pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) - 0 } +#[cfg(not(test))] #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { let _ = writeln!(libc::stdio::stderr(), "Panic: {}", info); diff --git a/src/system_alloc.rs b/src/system_alloc.rs index ad1afcb..7c0bac9 100644 --- a/src/system_alloc.rs +++ b/src/system_alloc.rs @@ -15,6 +15,7 @@ unsafe impl alloc::alloc::GlobalAlloc for System { #[global_allocator] static SYSTEM_ALLOC: System = System; +#[cfg(not(test))] #[alloc_error_handler] fn alloc_error(_: core::alloc::Layout) -> ! { panic!("allocation failure"); From 806ba1d0a866da7a60ca4e94b7209e85250e396c Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 24 May 2020 15:43:57 +0200 Subject: [PATCH 07/10] Update libc --- Cargo.lock | 4 ++-- safe_libc/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81b8dd6..e32d3ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "libc" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" +checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" [[package]] name = "neco" diff --git a/safe_libc/Cargo.toml b/safe_libc/Cargo.toml index 3741877..03d9b94 100644 --- a/safe_libc/Cargo.toml +++ b/safe_libc/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = { version = "0.2.69", default-features = false } +libc = { version = "0.2.70", default-features = false } From daf595fe5648250c2947947ba5d9cdf4ab24b403 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 24 May 2020 15:52:35 +0200 Subject: [PATCH 08/10] stdio: nicer error handling --- safe_libc/src/stdio.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/safe_libc/src/stdio.rs b/safe_libc/src/stdio.rs index be016ab..2942405 100644 --- a/safe_libc/src/stdio.rs +++ b/safe_libc/src/stdio.rs @@ -7,6 +7,12 @@ pub struct Error { pub errno: errno::Errno, } +impl From for fmt::Error { + fn from(_err: Error) -> fmt::Error { + fmt::Error + } +} + pub type Result = core::result::Result; #[inline] @@ -58,9 +64,7 @@ impl BasicOStream { impl fmt::Write for BasicOStream { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { - if self.write(s.as_bytes()).is_err() { - return Err(fmt::Error); - } + self.write(s.as_bytes())?; Ok(()) } } From 554275d78187657f2ff7099f8cffe66aa48289fd Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 30 May 2020 10:22:12 +0200 Subject: [PATCH 09/10] Update libc, remove redundant Cargo.lock --- Cargo.lock | 4 ++-- safe_libc/Cargo.lock | 14 -------------- safe_libc/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 safe_libc/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index e32d3ab..8675aaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "libc" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" [[package]] name = "neco" diff --git a/safe_libc/Cargo.lock b/safe_libc/Cargo.lock deleted file mode 100644 index b20b067..0000000 --- a/safe_libc/Cargo.lock +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "libc" -version = "0.2.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" - -[[package]] -name = "safe_libc" -version = "0.1.0" -dependencies = [ - "libc", -] diff --git a/safe_libc/Cargo.toml b/safe_libc/Cargo.toml index 03d9b94..34f8f79 100644 --- a/safe_libc/Cargo.toml +++ b/safe_libc/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = { version = "0.2.70", default-features = false } +libc = { version = "0.2.71", default-features = false } From 58260af4d8afd2079a50f2444e8bf721044d7a35 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 30 May 2020 10:22:35 +0200 Subject: [PATCH 10/10] Enable #[ffi_const] --- safe_libc/src/errno.rs | 2 +- safe_libc/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/safe_libc/src/errno.rs b/safe_libc/src/errno.rs index 2a2220b..fdb1246 100644 --- a/safe_libc/src/errno.rs +++ b/safe_libc/src/errno.rs @@ -7,7 +7,7 @@ use core::fmt; pub struct Errno(pub libc::c_int); extern "C" { - //#[ffi_const] + #[ffi_const] pub fn __errno_location() -> *mut libc::c_int; } diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs index 9356406..cbc4071 100644 --- a/safe_libc/src/lib.rs +++ b/safe_libc/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] #![feature(extern_types)] #![feature(slice_ptr_len)] -// #![feature(ffi_const)] +#![feature(ffi_const)] extern crate alloc;