diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/c/posix.rs | 7 | ||||
-rw-r--r-- | src/c/stdio.rs | 8 | ||||
-rw-r--r-- | src/c/string.rs | 144 | ||||
-rw-r--r-- | src/main.rs | 14 |
4 files changed, 130 insertions, 43 deletions
diff --git a/src/c/posix.rs b/src/c/posix.rs index 3933a2e..6b63ea7 100644 --- a/src/c/posix.rs +++ b/src/c/posix.rs @@ -1,8 +1,7 @@ extern "C" { pub fn strndup(cs: *const libc::c_char, n: libc::size_t) -> *mut libc::c_char; - pub static mut stdin: *mut libc::FILE; - pub static mut stdout: *mut libc::FILE; - pub static mut stderr: *mut libc::FILE; - + // pub static stdin: *mut libc::FILE; + pub static stdout: *mut libc::FILE; + pub static stderr: *mut libc::FILE; } diff --git a/src/c/stdio.rs b/src/c/stdio.rs index aa824ed..c878f19 100644 --- a/src/c/stdio.rs +++ b/src/c/stdio.rs @@ -7,8 +7,12 @@ pub struct OStream { file: *mut libc::FILE } -pub fn stdout() -> OStream { - OStream { file: unsafe { posix::stdout } } +pub unsafe fn stdout() -> OStream { + OStream { file: posix::stdout } +} + +pub unsafe fn stderr() -> OStream { + OStream { file: posix::stderr } } impl OStream { diff --git a/src/c/string.rs b/src/c/string.rs index eef6371..3d991dc 100644 --- a/src/c/string.rs +++ b/src/c/string.rs @@ -3,18 +3,20 @@ use core::{mem, ptr, slice}; use core::ops::{Deref, DerefMut}; fn must_succeed<T>(p: *mut T) -> *mut T { - if p.is_null() { - panic!("allocation failure"); - } + assert!(!p.is_null(), "allocation failure"); p } -fn malloc<T>() -> *mut T { - let size = mem::size_of::<T>(); - let align = mem::align_of::<T>(); - if size == 0 { - return align as *mut T; +fn zst<T>(count: usize) -> bool { + mem::size_of::<T>() == 0 || count == 0 +} + +fn alloc<T>(count: usize) -> *mut T { + if zst::<T>(count) { + return ptr::null_mut(); } + let size = count * mem::size_of::<T>(); + let align = mem::align_of::<T>(); must_succeed( unsafe { libc::memalign(align as libc::size_t, size as libc::size_t) as *mut T @@ -22,43 +24,91 @@ fn malloc<T>() -> *mut T { ) } -pub struct CBox<T>(*mut T); +fn dangling<T>() -> *mut T { + mem::align_of::<T>() as *mut T +} + +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"); +} + +fn slice_len<T>(p: *const [T]) -> usize { + unsafe { mem::transmute::<*const [T], [usize; 2]>(p)[1] } +} + +pub struct CBox<T: ?Sized>(*mut T); + +impl<T: ?Sized> CBox<T> { + pub unsafe fn from_raw_unchecked(p: *mut T) -> CBox<T> { + CBox(p) + } + + pub fn into_raw(self) -> *mut T { + let p = self.0; + mem::forget(self); + p + } + + pub fn as_ptr(&self) -> *const T { + self.0 + } + + pub fn as_mut_ptr(&mut self) -> *mut T { + self.0 + } +} impl<T> CBox<T> { pub fn new(value: T) -> CBox<T> { - let p = malloc(); + let p = alloc(1); unsafe { ptr::write(p, value); - CBox::from_raw(p) + CBox::from_raw_unchecked(p) } } - pub const unsafe fn from_raw(p: *mut T) -> CBox<T> { + pub unsafe fn from_raw(p: *mut T) -> CBox<T> { + check_ptr(p, 1); CBox(p) } - pub fn into_raw(self) -> *mut T { - let p = self.0; - mem::forget(self); - p + pub unsafe fn slice_from_raw_parts_unchecked(p: *mut T, len: usize) -> CBox<[T]> { + CBox(ptr::slice_from_raw_parts_mut(p, len)) } - pub const fn as_ptr(&self) -> *const T { + pub unsafe fn slice_from_raw_parts(p: *mut T, len: usize) -> CBox<[T]> { + check_ptr(p, len); + CBox::slice_from_raw_parts_unchecked(p, len) + } + + fn safe_ptr(&self) -> *mut T { + if self.0.is_null() { + debug_assert!(zst::<T>(1), "NULL ptr"); + return dangling(); + } + self.0 } +} + +impl<T> CBox<[T]> { + fn safe_ptr(&self) -> *mut [T] { + if self.0.is_null() { + let len = slice_len(self.0); + debug_assert!(zst::<T>(len), "NULL ptr"); + return ptr::slice_from_raw_parts_mut(dangling(), len); + } - pub fn as_mut_ptr(&mut self) -> *mut T { self.0 } } -impl<T> Drop for CBox<T> { +impl<T: ?Sized> Drop for CBox<T> { fn drop(&mut self) { - unsafe { ptr::drop_in_place(self.0); } - if mem::size_of::<T>() != 0 { - unsafe { - libc::free(self.0 as *mut libc::c_void); - } + unsafe { + ptr::drop_in_place(self.0); + libc::free(self.0 as *mut libc::c_void); } } } @@ -67,13 +117,27 @@ impl<T> Deref for CBox<T> { type Target = T; fn deref(&self) -> &T { - unsafe { &*self.0 } + unsafe { &*self.safe_ptr() } } } impl<T> DerefMut for CBox<T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.0 } + unsafe { &mut *self.safe_ptr() } + } +} + +impl<T> Deref for CBox<[T]> { + type Target = [T]; + + fn deref(&self) -> &[T] { + unsafe { &*self.safe_ptr() } + } +} + +impl<T> DerefMut for CBox<[T]> { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { &mut *self.safe_ptr() } } } @@ -82,16 +146,26 @@ impl<T> DerefMut for CBox<T> { pub struct CStr { inner: libc::c_char } impl CStr { - pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr { + pub unsafe fn from_ptr_unchecked<'a>(p: *const libc::c_char) -> &'a CStr { &*(p as *const CStr) } - pub unsafe fn from_ptr_mut<'a>(p: *mut libc::c_char) -> &'a mut CStr { + pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr { + check_ptr(p, 1); + CStr::from_ptr_unchecked(p) + } + + pub unsafe fn from_mut_ptr_unchecked<'a>(p: *mut libc::c_char) -> &'a mut CStr { &mut *(p as *mut CStr) } + pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr { + check_ptr(p, 1); + CStr::from_mut_ptr_unchecked(p) + } + pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { - CStr::from_ptr(bytes.as_ptr() as *const libc::c_char) + CStr::from_ptr_unchecked(bytes.as_ptr() as *const libc::c_char) } // TODO @@ -117,7 +191,7 @@ impl CStr { ) } } - pub fn as_bytes_mut(&mut self) -> &mut [u8] { + pub fn as_mut_bytes(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut( self.as_mut_ptr() as *mut u8, self.len(), @@ -139,6 +213,10 @@ macro_rules! cstr { pub struct CString { inner: CBox<libc::c_char> } impl CString { + pub unsafe fn from_raw_unchecked(p: *mut libc::c_char) -> CString { + CString { inner: CBox::from_raw_unchecked(p) } + } + pub unsafe fn from_raw(p: *mut libc::c_char) -> CString { CString { inner: CBox::from_raw(p) } } @@ -158,14 +236,14 @@ impl Deref for CString { impl DerefMut for CString { fn deref_mut(&mut self) -> &mut CStr { - unsafe { CStr::from_ptr_mut(&mut *self.inner) } + unsafe { CStr::from_mut_ptr(&mut *self.inner) } } } impl From<&[u8]> for CString { fn from(s: &[u8]) -> CString { unsafe { - CString::from_raw(must_succeed(posix::strndup( + CString::from_raw_unchecked(must_succeed(posix::strndup( s.as_ptr() as *const libc::c_char, s.len() as libc::size_t, ))) @@ -182,7 +260,7 @@ impl From<&str> for CString { impl From<&CStr> for CString { fn from(s: &CStr) -> CString { unsafe { - CString::from_raw(must_succeed(libc::strdup(s.as_ptr()))) + CString::from_raw_unchecked(must_succeed(libc::strdup(s.as_ptr()))) } } } diff --git a/src/main.rs b/src/main.rs index 15a2640..5f86a61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,16 +9,22 @@ 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 { c::stdio::stdout() }; let x = c::string::CString::from("foo"); - let y = c::string::CBox::new(x); + let l = x.len(); + let y = x.into_raw(); + let z = unsafe { + c::string::CBox::slice_from_raw_parts(y, l) + }; + //let y = unsafe { c::string::CBox::from_raw(x) }; //let foo = cstr!("Foo! %p\n"); //c::stdio::stdout().puts(foo); - let mut stdout = c::stdio::stdout(); - writeln!(stdout, "Foo: {}", 42); + let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]); 0 } #[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { +fn panic(info: &core::panic::PanicInfo) -> ! { + let _ = writeln!(unsafe { c::stdio::stderr() }, "Panic: {}", info); unsafe { libc::abort() } } |