summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2019-05-12 02:39:08 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2019-05-12 02:39:08 +0200
commit0abdc827c9aa9e3f64d31d62663ea232863e4e76 (patch)
tree47f3bcda0a0b9b6d2305953493f849faf31dfb80
downloadneco-0abdc827c9aa9e3f64d31d62663ea232863e4e76.tar
neco-0abdc827c9aa9e3f64d31d62663ea232863e4e76.zip
Safe libc test code
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock16
-rw-r--r--Cargo.toml14
-rw-r--r--src/c/mod.rs2
-rw-r--r--src/c/posix.rs8
-rw-r--r--src/c/string.rs188
-rw-r--r--src/main.rs19
7 files changed, 249 insertions, 0 deletions
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 <mschiffer@universe-factory.net>"]
+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<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())))
+ }
+ }
+}
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() }
+}