From 0abdc827c9aa9e3f64d31d62663ea232863e4e76 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 12 May 2019 02:39:08 +0200 Subject: Safe libc test code --- .gitignore | 2 + Cargo.lock | 16 +++++ Cargo.toml | 14 +++++ src/c/mod.rs | 2 + src/c/posix.rs | 8 +++ src/c/string.rs | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 19 ++++++ 7 files changed, 249 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/c/mod.rs create mode 100644 src/c/posix.rs create mode 100644 src/c/string.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0e3bca --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e536a5d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "libc" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "neco" +version = "0.1.0" +dependencies = [ + "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..769482b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "neco" +version = "0.1.0" +authors = ["Matthias Schiffer "] +edition = "2018" + +[dependencies] +libc = { version = "0.2.54", default-features = false } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" diff --git a/src/c/mod.rs b/src/c/mod.rs new file mode 100644 index 0000000..1b643c4 --- /dev/null +++ b/src/c/mod.rs @@ -0,0 +1,2 @@ +pub mod posix; +pub mod string; diff --git a/src/c/posix.rs b/src/c/posix.rs new file mode 100644 index 0000000..3933a2e --- /dev/null +++ b/src/c/posix.rs @@ -0,0 +1,8 @@ +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; + +} diff --git a/src/c/string.rs b/src/c/string.rs new file mode 100644 index 0000000..8babef6 --- /dev/null +++ b/src/c/string.rs @@ -0,0 +1,188 @@ +use super::posix; +use core::{mem, ptr, slice}; +use core::ops::{Deref, DerefMut}; + +const SENTINEL: *mut libc::c_void = 1 as *mut libc::c_void; + +fn must_succeed(p: *mut T) -> *mut T { + if p.is_null() { + panic!("allocation failure"); + } + p +} + +unsafe fn malloc() -> *mut T { + let size = mem::size_of::(); + /*if size == 0 { + return SENTINEL as *mut T; + }*/ + must_succeed(0 as *mut T) + /*must_succeed( + libc::memalign(mem::align_of::() as libc::size_t, size as libc::size_t) + ) as *mut T*/ +} + +pub struct CBox(*mut T); + +impl CBox { + pub const unsafe fn from_raw(p: *mut T) -> CBox { + CBox(p) + } + + pub fn into_raw(self) -> *mut T { + let p = self.0; + mem::forget(self); + p + } + + pub const fn as_ptr(&self) -> *const T { + self.0 + } + + pub fn as_mut_ptr(&mut self) -> *mut T { + self.0 + } +} + +impl CBox { + pub fn new(value: T) -> CBox { + unsafe { + let p = malloc(); + ptr::write(p, value); + CBox::from_raw(p) + } + } +} + +impl Drop for CBox { + fn drop(&mut self) { + let p = self.0 as *mut libc::c_void; + if p != SENTINEL { + unsafe { libc::free(p); } + } + } +} + +impl Deref for CBox { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} + +impl DerefMut for CBox { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.0 } + } +} + +//pub struct FromBytesWithNulError {} + +pub struct CStr { inner: libc::c_char } + +impl CStr { + pub unsafe fn from_ptr<'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 { + &mut *(p as *mut CStr) + } + + pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + CStr::from_ptr(bytes.as_ptr() as *const libc::c_char) + } + + // TODO + //pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { + //} + + pub fn len(&self) -> usize { + unsafe { libc::strlen(self.as_ptr()) as usize } + } + + pub const fn as_ptr(&self) -> *const libc::c_char { + &self.inner + } + + pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { + &mut self.inner + } + + pub fn as_bytes(&self) -> &[u8] { + unsafe { slice::from_raw_parts( + self.as_ptr() as *const u8, + self.len(), + ) } + } + + pub fn as_bytes_mut(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut( + self.as_mut_ptr() as *mut u8, + self.len(), + ) } + } + + pub fn to_owned(self: &CStr) -> CString { + CString::from(self) + } +} + +#[macro_export] +macro_rules! cstr { + ($s:expr) => ( + unsafe { $crate::c::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) } + ) +} + +pub struct CString { inner: CBox } + +impl CString { + pub unsafe fn from_raw(p: *mut libc::c_char) -> CString { + CString { inner: CBox::from_raw(p) } + } + + pub fn into_raw(self) -> *mut libc::c_char { + self.inner.into_raw() + } +} + +impl Deref for CString { + type Target = CStr; + + fn deref(&self) -> &CStr { + unsafe { CStr::from_ptr(&*self.inner) } + } +} + +impl DerefMut for CString { + fn deref_mut(&mut self) -> &mut CStr { + unsafe { CStr::from_ptr_mut(&mut *self.inner) } + } +} + +impl From<&[u8]> for CString { + fn from(s: &[u8]) -> CString { + unsafe { + CString::from_raw(must_succeed(posix::strndup( + s.as_ptr() as *const libc::c_char, + s.len() as libc::size_t, + ))) + } + } +} + +impl From<&str> for CString { + fn from(s: &str) -> CString { + CString::from(s.as_bytes()) + } +} + +impl From<&CStr> for CString { + fn from(s: &CStr) -> CString { + unsafe { + CString::from_raw(must_succeed(libc::strdup(s.as_ptr()))) + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7cdfb3f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,19 @@ +#![no_main] +#![no_std] + +extern crate libc; + +mod c; + +#[no_mangle] +pub extern fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int { + let foo = cstr!("Foo! %p\n"); + let x = c::string::CBox::new(()); + unsafe { libc::printf(foo.as_ptr(), &*x as *const ()); } + 0 +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + unsafe { libc::abort() } +} -- cgit v1.2.3