Safe libc test code

This commit is contained in:
Matthias Schiffer 2019-05-12 02:39:08 +02:00
commit 0abdc827c9
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
7 changed files with 249 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
**/*.rs.bk

16
Cargo.lock generated Normal file
View file

@ -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"

14
Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "neco"
version = "0.1.0"
authors = ["Matthias Schiffer <mschiffer@universe-factory.net>"]
edition = "2018"
[dependencies]
libc = { version = "0.2.54", default-features = false }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"

2
src/c/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod posix;
pub mod string;

8
src/c/posix.rs Normal file
View file

@ -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;
}

188
src/c/string.rs Normal file
View file

@ -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<T>(p: *mut T) -> *mut T {
if p.is_null() {
panic!("allocation failure");
}
p
}
unsafe fn malloc<T>() -> *mut T {
let size = mem::size_of::<T>();
/*if size == 0 {
return SENTINEL as *mut T;
}*/
must_succeed(0 as *mut T)
/*must_succeed(
libc::memalign(mem::align_of::<T>() as libc::size_t, size as libc::size_t)
) as *mut T*/
}
pub struct CBox<T: ?Sized>(*mut T);
impl<T: ?Sized> CBox<T> {
pub const unsafe fn from_raw(p: *mut T) -> CBox<T> {
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<T> CBox<T> {
pub fn new(value: T) -> CBox<T> {
unsafe {
let p = malloc();
ptr::write(p, value);
CBox::from_raw(p)
}
}
}
impl<T: ?Sized> Drop for CBox<T> {
fn drop(&mut self) {
let p = self.0 as *mut libc::c_void;
if p != SENTINEL {
unsafe { libc::free(p); }
}
}
}
impl<T: ?Sized> Deref for CBox<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0 }
}
}
impl<T: ?Sized> DerefMut for CBox<T> {
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<libc::c_char> }
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())))
}
}
}

19
src/main.rs Normal file
View file

@ -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() }
}