From bd6cc20a755f88daeaffd04f24d1e6b9b8acb46d Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Sun, 9 Apr 2023 16:53:04 +0200
Subject: [PATCH] Make pthread types opaque, and check against libc.

---
 Cargo.lock                     |   3 +-
 Cargo.toml                     |   7 +-
 src/header/bits_pthread/mod.rs | 126 ++++++++++++++++++++-------------
 src/header/bits_sched/mod.rs   |   6 --
 src/header/pthread/attr.rs     |  45 ++++++------
 src/header/pthread/barrier.rs  |  23 ++++--
 src/header/pthread/cond.rs     |  35 ++++++---
 src/header/pthread/mod.rs      |  14 +++-
 src/header/pthread/mutex.rs    |  51 +++++++++----
 src/header/pthread/once.rs     |   8 ++-
 src/header/pthread/rwlock.rs   |  34 ++++++---
 src/header/pthread/spin.rs     |  29 ++++++--
 src/header/sched/mod.rs        |   9 ++-
 src/pthread/mod.rs             |   2 +-
 14 files changed, 260 insertions(+), 132 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 1a00975c5..72bbd7cf3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -228,8 +228,6 @@ version = "0.1.0"
 [[package]]
 name = "libc"
 version = "0.2.141"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
 
 [[package]]
 name = "linux-raw-sys"
@@ -407,6 +405,7 @@ dependencies = [
  "core_io",
  "goblin",
  "lazy_static",
+ "libc",
  "memchr",
  "memoffset",
  "plain",
diff --git a/Cargo.toml b/Cargo.toml
index 856da184c..41e0ddbfb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,6 +28,7 @@ rand = { version = "0.5.5", default-features = false }
 memchr = { version = "2.2.0", default-features = false }
 plain = "0.2"
 unicode-width = "0.1"
+libc = { version = "0.2", optional = true }
 
 [dependencies.goblin]
 version = "0.0.21"
@@ -48,11 +49,15 @@ spin = "0.9.0"
 redox-exec = { path = "src/platform/redox/redox-exec" }
 
 [features]
-default = []
+default = ["check_against_libc_crate"]
 trace = []
+check_against_libc_crate = ["libc"]
 
 [profile.dev]
 panic = "abort"
 
 [profile.release]
 panic = "abort"
+
+[patch.crates-io]
+libc = { path = "/home/me/Projects/libc" }
diff --git a/src/header/bits_pthread/mod.rs b/src/header/bits_pthread/mod.rs
index 1f8729942..e3dc67bf2 100644
--- a/src/header/bits_pthread/mod.rs
+++ b/src/header/bits_pthread/mod.rs
@@ -7,75 +7,105 @@ use crate::header::sched::sched_param;
 use crate::sync::AtomicLock;
 use core::sync::atomic::{AtomicU32 as AtomicUint, AtomicI32 as AtomicInt};
 
+// XXX: https://github.com/eqrion/cbindgen/issues/685
+//
+// We need to write the opaque types ourselves, and apparently cbindgen doesn't even support
+// expanding macros! Instead, we rely on checking that the lengths are correct, when these headers
+// are parsed in the regular compilation phase.
+
 #[repr(C)]
-#[derive(Clone, Copy)]
-pub struct pthread_attr_t {
-    pub detachstate: c_uchar,
-    pub inheritsched: c_uchar,
-    pub schedpolicy: c_uchar,
-    pub scope: c_uchar,
-    pub guardsize: size_t,
-    pub stacksize: size_t,
-    pub stack: size_t,
-    pub param: sched_param,
+pub union pthread_attr_t {
+    __relibc_internal_size: [c_uchar; 32],
+    __relibc_internal_align: c_long,
 }
-
 #[repr(C)]
-pub struct pthread_rwlockattr_t {
-    pub pshared: c_int,
+pub union pthread_rwlockattr_t {
+    __relibc_internal_size: [c_uchar; 4],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_rwlock_t {
-    pub state: AtomicInt,
+pub union pthread_rwlock_t {
+    __relibc_internal_size: [c_uchar; 4],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_barrier_t {
-    pub count: AtomicUint,
-    pub original_count: c_uint,
-    pub epoch: AtomicInt,
+pub union pthread_barrier_t {
+    __relibc_internal_size: [c_uchar; 12],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_barrierattr_t {
-    pub pshared: c_int,
+pub union pthread_barrierattr_t {
+    __relibc_internal_size: [c_uchar; 4],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_mutex_t {
-    pub inner: AtomicInt,
+pub union pthread_mutex_t {
+    __relibc_internal_size: [c_uchar; 4],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_mutexattr_t {
-    pub prioceiling: c_int,
-    pub protocol: c_int,
-    pub pshared: c_int,
-    pub robust: c_int,
-    pub ty: c_int,
+pub union pthread_mutexattr_t {
+    __relibc_internal_size: [c_uchar; 20],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_condattr_t {
-    pub clock: clockid_t,
-    pub pshared: c_int,
+pub union pthread_cond_t {
+    __relibc_internal_size: [c_uchar; 8],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_cond_t {
-    pub cur: AtomicInt,
-    pub prev: AtomicInt,
+pub union pthread_condattr_t {
+    __relibc_internal_size: [c_uchar; 8],
+    __relibc_internal_align: c_int,
 }
 #[repr(C)]
-pub struct pthread_spinlock_t {
-    pub inner: AtomicInt,
+pub union pthread_spinlock_t {
+    __relibc_internal_size: [c_uchar; 4],
+    __relibc_internal_align: c_int,
 }
-
 #[repr(C)]
-pub struct pthread_once_t {
-    pub inner: AtomicInt,
+pub union pthread_once_t {
+    __relibc_internal_size: [c_uchar; 4],
+    __relibc_internal_align: c_int,
 }
 
-pub type pthread_t = *mut ();
+macro_rules! assert_equal_size(
+    ($export:ident, $wrapped:ident) => {
+        const _: () = unsafe {
+            type Wrapped = crate::header::pthread::$wrapped;
+
+            // Fail at compile-time if sizes differ.
+
+            // TODO: Is this UB?
+            let export = $export { __relibc_internal_align: 0 };
+            let _: Wrapped = core::mem::transmute(export.__relibc_internal_size);
+
+            // Fail at compile-time if alignments differ.
+            let a = [0_u8; core::mem::align_of::<$export>()];
+            let b: [u8; core::mem::align_of::<Wrapped>()] = core::mem::transmute(a);
+        };
+        #[cfg(feature = "check_against_libc_crate")]
+        const _: () = unsafe {
+            let export = $export { __relibc_internal_align: 0 };
+            let _: libc::$export = core::mem::transmute(export.__relibc_internal_size); 
+
+            let a = [0_u8; core::mem::align_of::<$export>()];
+            let b: [u8; core::mem::align_of::<libc::$export>()] = core::mem::transmute(a);
+
+        };
+    }
+);
+assert_equal_size!(pthread_attr_t, RlctAttr);
+assert_equal_size!(pthread_rwlock_t, RlctRwlock);
+assert_equal_size!(pthread_rwlock_t, RlctRwlockAttr);
+assert_equal_size!(pthread_barrier_t, RlctBarrier);
+assert_equal_size!(pthread_barrierattr_t, RlctBarrierAttr);
+assert_equal_size!(pthread_mutex_t, RlctMutex);
+assert_equal_size!(pthread_mutexattr_t, RlctMutexAttr);
+assert_equal_size!(pthread_cond_t, RlctCond);
+assert_equal_size!(pthread_condattr_t, RlctCondAttr);
+assert_equal_size!(pthread_spinlock_t, RlctSpinlock);
+assert_equal_size!(pthread_once_t, RlctOnce);
+
+pub type pthread_t = *mut c_void;
 pub type pthread_key_t = c_ulong;
diff --git a/src/header/bits_sched/mod.rs b/src/header/bits_sched/mod.rs
index b092dbdd7..149fc8eb0 100644
--- a/src/header/bits_sched/mod.rs
+++ b/src/header/bits_sched/mod.rs
@@ -1,9 +1,3 @@
 #![allow(non_camel_case_types)]
 
 use crate::platform::types::*;
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct sched_param {
-    pub sched_priority: c_int,
-}
diff --git a/src/header/pthread/attr.rs b/src/header/pthread/attr.rs
index a13dac614..b9f727945 100644
--- a/src/header/pthread/attr.rs
+++ b/src/header/pthread/attr.rs
@@ -2,7 +2,7 @@ use super::*;
 
 use crate::header::bits_pthread::pthread_attr_t;
 
-impl Default for pthread_attr_t {
+impl Default for RlctAttr {
     fn default() -> Self {
         Self {
             // Default according to POSIX.
@@ -28,110 +28,113 @@ impl Default for pthread_attr_t {
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut pthread_attr_t) -> c_int {
+pub unsafe extern "C" fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> c_int {
+    let _attr = &mut *attr.cast::<RlctAttr>();
+
+    // No-op
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getdetachstate(attr: *const pthread_attr_t, detachstate: *mut c_int) -> c_int {
-    core::ptr::write(detachstate, (*attr).detachstate as _);
+    core::ptr::write(detachstate, (*attr.cast::<RlctAttr>()).detachstate as _);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getguardsize(attr: *const pthread_attr_t, size: *mut size_t) -> c_int {
-    core::ptr::write(size, (*attr).guardsize);
+    core::ptr::write(size, (*attr.cast::<RlctAttr>()).guardsize);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getinheritsched(attr: *const pthread_attr_t, inheritsched: *mut c_int) -> c_int {
-    core::ptr::write(inheritsched, (*attr).inheritsched as _);
+    core::ptr::write(inheritsched, (*attr.cast::<RlctAttr>()).inheritsched as _);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getschedparam(attr: *const pthread_attr_t, param: *mut sched_param) -> c_int {
-    core::ptr::write(param, (*attr).param);
+    param.write((*attr.cast::<RlctAttr>()).param);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getschedpolicy(attr: *const pthread_attr_t, policy: *mut c_int) -> c_int {
-    core::ptr::write(policy, (*attr).schedpolicy as _);
+    core::ptr::write(policy, (*attr.cast::<RlctAttr>()).schedpolicy as _);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getscope(attr: *const pthread_attr_t, scope: *mut c_int) -> c_int {
-    core::ptr::write(scope, (*attr).scope as _);
+    core::ptr::write(scope, (*attr.cast::<RlctAttr>()).scope as _);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getstack(attr: *const pthread_attr_t, stackaddr: *mut *mut c_void, stacksize: *mut size_t) -> c_int {
-    core::ptr::write(stackaddr, (*attr).stack as _);
-    core::ptr::write(stacksize, (*attr).stacksize as _);
+    core::ptr::write(stackaddr, (*attr.cast::<RlctAttr>()).stack as _);
+    core::ptr::write(stacksize, (*attr.cast::<RlctAttr>()).stacksize as _);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_getstacksize(attr: *const pthread_attr_t, stacksize: *mut c_int) -> c_int {
-    core::ptr::write(stacksize, (*attr).stacksize as _);
+    core::ptr::write(stacksize, (*attr.cast::<RlctAttr>()).stacksize as _);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int {
-    core::ptr::write(attr, pthread_attr_t::default());
+    core::ptr::write(attr.cast::<RlctAttr>(), RlctAttr::default());
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, detachstate: c_int) -> c_int {
-    (*attr).detachstate = detachstate as _;
+    (*attr.cast::<RlctAttr>()).detachstate = detachstate as _;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setguardsize(attr: *mut pthread_attr_t, guardsize: c_int) -> c_int {
-    (*attr).guardsize = guardsize as _;
+    (*attr.cast::<RlctAttr>()).guardsize = guardsize as _;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setinheritsched(attr: *mut pthread_attr_t, inheritsched: c_int) -> c_int {
-    (*attr).inheritsched = inheritsched as _;
+    (*attr.cast::<RlctAttr>()).inheritsched = inheritsched as _;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setschedparam(attr: *mut pthread_attr_t, param: *const sched_param) -> c_int {
-    (*attr).param = core::ptr::read(param);
+    (*attr.cast::<RlctAttr>()).param = param.read();
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setschedpolicy(attr: *mut pthread_attr_t, policy: c_int) -> c_int {
-    (*attr).schedpolicy = policy as u8;
+    (*attr.cast::<RlctAttr>()).schedpolicy = policy as u8;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setscope(attr: *mut pthread_attr_t, scope: c_int) -> c_int {
-    (*attr).scope = scope as u8;
+    (*attr.cast::<RlctAttr>()).scope = scope as u8;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setstack(attr: *mut pthread_attr_t, stackaddr: *mut c_void, stacksize: size_t) -> c_int {
-    (*attr).stack = stackaddr as usize;
-    (*attr).stacksize = stacksize;
+    (*attr.cast::<RlctAttr>()).stack = stackaddr as usize;
+    (*attr.cast::<RlctAttr>()).stacksize = stacksize;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, stacksize: size_t) -> c_int {
-    (*attr).stacksize = stacksize;
+    (*attr.cast::<RlctAttr>()).stacksize = stacksize;
     0
 }
diff --git a/src/header/pthread/barrier.rs b/src/header/pthread/barrier.rs
index 3e32ca4ab..630d9b4d5 100644
--- a/src/header/pthread/barrier.rs
+++ b/src/header/pthread/barrier.rs
@@ -1,9 +1,18 @@
 use crate::header::errno::*;
 
-use core::sync::atomic::{AtomicU32, AtomicI32 as AtomicInt, Ordering};
+use core::sync::atomic::{AtomicU32 as AtomicUint, AtomicI32 as AtomicInt, Ordering};
 
 use super::*;
 
+pub(crate) struct RlctBarrier {
+    pub count: AtomicUint,
+    pub original_count: c_uint,
+    pub epoch: AtomicInt,
+}
+pub(crate) struct RlctBarrierAttr {
+    pub pshared: c_int,
+}
+
 #[no_mangle]
 pub unsafe extern "C" fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t) -> c_int {
     // Behavior is undefined if any thread is currently waiting.
@@ -12,12 +21,14 @@ pub unsafe extern "C" fn pthread_barrier_destroy(barrier: *mut pthread_barrier_t
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_barrier_init(barrier: *mut pthread_barrier_t, attr: *const pthread_barrierattr_t, count: c_uint) -> c_int {
+    let attr = attr.cast::<RlctBarrierAttr>().as_ref();
+
     if count == 0 {
         return EINVAL;
     }
 
-    core::ptr::write(barrier, pthread_barrier_t {
-        count: AtomicU32::new(0),
+    barrier.cast::<RlctBarrier>().write(RlctBarrier {
+        count: AtomicUint::new(0),
         original_count: count,
         epoch: AtomicInt::new(0),
     });
@@ -26,7 +37,7 @@ pub unsafe extern "C" fn pthread_barrier_init(barrier: *mut pthread_barrier_t, a
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -> c_int {
-    let barrier: &pthread_barrier_t = &*barrier;
+    let barrier = &*barrier.cast::<RlctBarrier>();
 
     // TODO: Orderings
     let mut cached = barrier.count.load(Ordering::SeqCst);
@@ -60,13 +71,13 @@ pub unsafe extern "C" fn pthread_barrier_wait(barrier: *mut pthread_barrier_t) -
 #[no_mangle]
 pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int {
     // PTHREAD_PROCESS_PRIVATE is default according to POSIX.
-    core::ptr::write(attr, pthread_barrierattr_t { pshared: PTHREAD_PROCESS_PRIVATE });
+    core::ptr::write(attr.cast::<RlctBarrierAttr>(), RlctBarrierAttr { pshared: PTHREAD_PROCESS_PRIVATE });
 
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_barrierattr_setpshared(attr: *mut pthread_barrierattr_t, pshared: c_int) -> c_int {
-    (*attr).pshared = pshared;
+    (*attr.cast::<RlctBarrierAttr>()).pshared = pshared;
     0
 }
diff --git a/src/header/pthread/cond.rs b/src/header/pthread/cond.rs
index 545d918a4..25d2faf5a 100644
--- a/src/header/pthread/cond.rs
+++ b/src/header/pthread/cond.rs
@@ -12,7 +12,7 @@ pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_
 }
 
 unsafe fn wake(cond: *mut pthread_cond_t, n: i32) -> c_int {
-    let cond: &pthread_cond_t = &*cond;
+    let cond = &*cond.cast::<RlctCond>();
 
     // This is formally correct as long as we don't have more than u32::MAX threads.
     let prev = cond.prev.load(Ordering::SeqCst);
@@ -25,13 +25,15 @@ unsafe fn wake(cond: *mut pthread_cond_t, n: i32) -> c_int {
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int {
-    let _cond: &pthread_cond_t = &*cond;
+    let _cond = &mut cond.cast::<RlctCond>();
+
+    // No-op
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_cond_init(cond: *mut pthread_cond_t, _attr: *const pthread_condattr_t) -> c_int {
-    cond.write(pthread_cond_t {
+    cond.cast::<RlctCond>().write(RlctCond {
         cur: AtomicInt::new(0),
         prev: AtomicInt::new(0),
     });
@@ -47,11 +49,11 @@ pub unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int
 pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex_ptr: *mut pthread_mutex_t, timeout: *const timespec) -> c_int {
     // TODO: Error checking for certain types (i.e. robust and errorcheck) of mutexes, e.g. if the
     // mutex is not locked.
-    let cond: &pthread_cond_t = &*cond;
+    let cond = &*cond.cast::<RlctCond>();
     let timeout: Option<&timespec> = timeout.as_ref();
 
     let current = cond.cur.load(Ordering::Relaxed);
-    cond.prev.store(current, Ordering::SeqCst);
+    cond.prev.store(current, Ordering::SeqCst); // TODO: ordering?
 
     pthread_mutex_unlock(mutex_ptr);
     crate::sync::futex_wait(&cond.cur, current, timeout);
@@ -67,41 +69,54 @@ pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mu
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_condattr_destroy(condattr: *mut pthread_condattr_t) -> c_int {
+    let _condattr = &mut *condattr.cast::<RlctCondAttr>();
+
+    // No-op
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_condattr_getclock(condattr: *const pthread_condattr_t, clock: *mut clockid_t) -> c_int {
-    core::ptr::write(clock, (*condattr).clock);
+    core::ptr::write(clock, (*condattr.cast::<RlctCondAttr>()).clock);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_condattr_getpshared(condattr: *const pthread_condattr_t, pshared: *mut c_int) -> c_int {
-    core::ptr::write(pshared, (*condattr).pshared);
+    core::ptr::write(pshared, (*condattr.cast::<RlctCondAttr>()).pshared);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_condattr_init(condattr: *mut pthread_condattr_t) -> c_int {
-    core::ptr::write(condattr, pthread_condattr_t {
+    condattr.cast::<RlctCondAttr>().write(RlctCondAttr {
         // FIXME: system clock
         clock: 0,
         // Default
         pshared: PTHREAD_PROCESS_PRIVATE,
     });
+
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_condattr_setclock(condattr: *mut pthread_condattr_t, clock: clockid_t) -> c_int {
-    (*condattr).clock = clock;
+    (*condattr.cast::<RlctCondAttr>()).clock = clock;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_condattr_setpshared(condattr: *mut pthread_condattr_t, pshared: c_int) -> c_int {
-    (*condattr).pshared = pshared;
+    (*condattr.cast::<RlctCondAttr>()).pshared = pshared;
     0
 }
 
+pub(crate) struct RlctCondAttr {
+    pub clock: clockid_t,
+    pub pshared: c_int,
+}
+
+pub(crate) struct RlctCond {
+    pub cur: AtomicInt,
+    pub prev: AtomicInt,
+}
diff --git a/src/header/pthread/mod.rs b/src/header/pthread/mod.rs
index 7bdf7de4d..ea6d3f150 100644
--- a/src/header/pthread/mod.rs
+++ b/src/header/pthread/mod.rs
@@ -6,6 +6,18 @@ use crate::platform::{self, Pal, Sys, types::*};
 use crate::header::{sched::*, time::timespec};
 use crate::pthread;
 
+#[derive(Clone, Copy)]
+pub(crate) struct RlctAttr {
+    pub detachstate: c_uchar,
+    pub inheritsched: c_uchar,
+    pub schedpolicy: c_uchar,
+    pub scope: c_uchar,
+    pub guardsize: size_t,
+    pub stacksize: size_t,
+    pub stack: size_t,
+    pub param: sched_param,
+}
+
 pub const PTHREAD_BARRIER_SERIAL_THREAD: c_int = 1;
 
 pub const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 0;
@@ -59,7 +71,7 @@ pub use self::cond::*;
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_create(pthread: *mut pthread_t, attr: *const pthread_attr_t, start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, arg: *mut c_void) -> c_int {
-    let attr = NonNull::new(attr as *mut _).map(|n| n.as_ref());
+    let attr = attr.cast::<RlctAttr>().as_ref();
 
     match pthread::create(attr, start_routine, arg) {
         Ok(ptr) => {
diff --git a/src/header/pthread/mutex.rs b/src/header/pthread/mutex.rs
index 3ea242e74..c5490cdbc 100644
--- a/src/header/pthread/mutex.rs
+++ b/src/header/pthread/mutex.rs
@@ -2,6 +2,8 @@ use super::*;
 
 use crate::header::errno::EBUSY;
 
+use core::sync::atomic::AtomicI32 as AtomicInt;
+
 // PTHREAD_MUTEX_INITIALIZER
 
 // #[no_mangle]
@@ -20,15 +22,19 @@ pub extern "C" fn pthread_mutex_getprioceiling(mutex: *const pthread_mutex_t, pr
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, _attr: *const pthread_mutexattr_t) -> c_int {
+pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) -> c_int {
+    let attr = attr.cast::<RlctMutexAttr>().as_ref();
+
     // TODO: attr
-    mutex.write(pthread_mutex_t {
+    mutex.cast::<RlctMutex>().write(RlctMutex {
         inner: crate::sync::mutex::UNLOCKED.into(),
     });
     0
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
+    let mutex = &*mutex.cast::<RlctMutex>();
+
     crate::sync::mutex::manual_lock_generic(&(&*mutex).inner);
 
     0
@@ -45,6 +51,8 @@ pub extern "C" fn pthread_mutex_timedlock(mutex: *mut pthread_mutex_t, timespec:
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int {
+    let mutex = &*mutex.cast::<RlctMutex>();
+
     if crate::sync::mutex::manual_try_lock_generic(&(&*mutex).inner) {
         0
     } else {
@@ -53,6 +61,8 @@ pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
+    let mutex = &*mutex.cast::<RlctMutex>();
+
     crate::sync::mutex::manual_unlock_generic(&(&*mutex).inner);
     0
 }
@@ -64,35 +74,35 @@ pub extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) ->
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_getprioceiling(attr: *const pthread_mutexattr_t, prioceiling: *mut c_int) -> c_int {
-    prioceiling.write((*attr).prioceiling);
+    prioceiling.write((*attr.cast::<RlctMutexAttr>()).prioceiling);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_getprotocol(attr: *const pthread_mutexattr_t, protocol: *mut c_int) -> c_int {
-    protocol.write((*attr).protocol);
+    protocol.write((*attr.cast::<RlctMutexAttr>()).protocol);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, pshared: *mut c_int) -> c_int {
-    pshared.write((*attr).pshared);
+    pshared.write((*attr.cast::<RlctMutexAttr>()).pshared);
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_getrobust(attr: *const pthread_mutexattr_t, robust: *mut c_int) -> c_int {
-    robust.write((*attr).robust);
+    robust.write((*attr.cast::<RlctMutexAttr>()).robust);
     0
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_gettype(attr: *const pthread_mutexattr_t, ty: *mut c_int) -> c_int {
-    ty.write((*attr).ty);
+    ty.write((*attr.cast::<RlctMutexAttr>()).ty);
     0
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
-    attr.write(pthread_mutexattr_t {
+    attr.cast::<RlctMutexAttr>().write(RlctMutexAttr {
         robust: PTHREAD_MUTEX_STALLED,
         pshared: PTHREAD_PROCESS_PRIVATE,
         protocol: PTHREAD_PRIO_NONE,
@@ -105,29 +115,44 @@ pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t)
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_setprioceiling(attr: *mut pthread_mutexattr_t, prioceiling: c_int) -> c_int {
-    (*attr).prioceiling = prioceiling;
+    (*attr.cast::<RlctMutexAttr>()).prioceiling = prioceiling;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int {
-    (*attr).protocol = protocol;
+    (*attr.cast::<RlctMutexAttr>()).protocol = protocol;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, pshared: c_int) -> c_int {
-    (*attr).pshared = pshared;
+    (*attr.cast::<RlctMutexAttr>()).pshared = pshared;
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_setrobust(attr: *mut pthread_mutexattr_t, robust: c_int) -> c_int {
-    (*attr).robust = robust;
+    (*attr.cast::<RlctMutexAttr>()).robust = robust;
     0
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, ty: c_int) -> c_int {
-    (*attr).ty = ty;
+    (*attr.cast::<RlctMutexAttr>()).ty = ty;
     0
 }
+
+#[repr(C)]
+pub(crate) struct RlctMutex {
+    pub inner: AtomicInt,
+}
+
+#[repr(C)]
+pub(crate) struct RlctMutexAttr {
+    pub prioceiling: c_int,
+    pub protocol: c_int,
+    pub pshared: c_int,
+    pub robust: c_int,
+    pub ty: c_int,
+}
+
diff --git a/src/header/pthread/once.rs b/src/header/pthread/once.rs
index 9bb96616f..28400ae6c 100644
--- a/src/header/pthread/once.rs
+++ b/src/header/pthread/once.rs
@@ -4,10 +4,14 @@ use super::*;
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_once(once: *mut pthread_once_t, constructor: extern "C" fn()) -> c_int {
-    let once: &pthread_once_t = &*once;
+    let once = &*once.cast::<RlctOnce>();
 
     // TODO: Cancellation points
-    crate::sync::once::call_once_generic(&once.inner, || constructor());
+
+    once.call_once(|| constructor());
+
+    //crate::sync::once::call_once_generic(&once.inner, || constructor());
 
     0
 }
+pub(crate) type RlctOnce = crate::sync::Once<()>;
diff --git a/src/header/pthread/rwlock.rs b/src/header/pthread/rwlock.rs
index be2fbf274..6303e3eab 100644
--- a/src/header/pthread/rwlock.rs
+++ b/src/header/pthread/rwlock.rs
@@ -21,8 +21,10 @@ pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut pthread_rwlock_t) -
     0
 }
 #[no_mangle]
-pub unsafe extern "C" fn pthread_rwlock_init(rwlock: *mut pthread_rwlock_t, _attr: *const pthread_rwlockattr_t) -> c_int {
-    core::ptr::write(rwlock, pthread_rwlock_t {
+pub unsafe extern "C" fn pthread_rwlock_init(rwlock: *mut pthread_rwlock_t, attr: *const pthread_rwlockattr_t) -> c_int {
+    let attr = attr.cast::<RlctRwlockAttr>().as_ref();
+
+    rwlock.cast::<RlctRwlock>().write(RlctRwlock {
         state: AtomicInt::new(0),
     });
 
@@ -34,7 +36,7 @@ pub unsafe extern "C" fn pthread_rwlock_rdlock(rwlock: *mut pthread_rwlock_t) ->
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rwlock: *mut pthread_rwlock_t, timeout: *const timespec) -> c_int {
-    let rwlock: &pthread_rwlock_t = &*rwlock;
+    let rwlock = &*rwlock.cast::<RlctRwlock>();
     let timeout = timeout.as_ref();
 
     loop {
@@ -46,7 +48,7 @@ pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rwlock: *mut pthread_rwlock_
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rwlock: *mut pthread_rwlock_t, timeout: *const timespec) -> c_int {
-    let rwlock: &pthread_rwlock_t = &*rwlock;
+    let rwlock = &*rwlock.cast::<RlctRwlock>();
     let timeout = timeout.as_ref();
 
     /*loop {
@@ -67,7 +69,7 @@ pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rwlock: *mut pthread_rwlock_
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut pthread_rwlock_t) -> c_int {
-    let rwlock: &pthread_rwlock_t = &*rwlock;
+    let rwlock = &*rwlock.cast::<RlctRwlock>();
 
     let mut cached = rwlock.state.load(Ordering::Acquire) as u32;
 
@@ -89,7 +91,7 @@ pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut pthread_rwlock_t)
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlock_trywrlock(rwlock: *mut pthread_rwlock_t) -> c_int {
-    let rwlock: &pthread_rwlock_t = &*rwlock;
+    let rwlock = &*rwlock.cast::<RlctRwlock>();
 
     match rwlock.state.compare_exchange(0, EXCLUSIVE as i32, Ordering::Acquire, Ordering::Relaxed) {
         Ok(_) => 0,
@@ -98,7 +100,7 @@ pub unsafe extern "C" fn pthread_rwlock_trywrlock(rwlock: *mut pthread_rwlock_t)
 }
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *const pthread_rwlock_t) -> c_int {
-    let rwlock: &pthread_rwlock_t = &*rwlock;
+    let rwlock = &*rwlock.cast::<RlctRwlock>();
 
     let old = rwlock.state.swap(0, Ordering::Release) as u32;
 
@@ -114,20 +116,23 @@ pub unsafe extern "C" fn pthread_rwlock_wrlock(rwlock: *mut pthread_rwlock_t) ->
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn pthread_rwlockattr_destroy(_attr: *mut pthread_rwlockattr_t) -> c_int {
+pub unsafe extern "C" fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) -> c_int {
+    let _attr = &mut *attr.cast::<RlctRwlockAttr>();
+
+    // No-op
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, pshared: *mut c_int) -> c_int {
-    core::ptr::write(pshared, (*attr).pshared);
+    core::ptr::write(pshared, (*attr.cast::<RlctRwlockAttr>()).pshared);
 
     0
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int {
-    core::ptr::write(attr, pthread_rwlockattr_t {
+    attr.cast::<RlctRwlockAttr>().write(RlctRwlockAttr {
         // Default according to POSIX.
         pshared: PTHREAD_PROCESS_PRIVATE,
     });
@@ -137,6 +142,13 @@ pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t
 
 #[no_mangle]
 pub unsafe extern "C" fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, pshared: c_int) -> c_int {
-    (*attr).pshared = pshared;
+    (*attr.cast::<RlctRwlockAttr>()).pshared = pshared;
     0
 }
+
+pub(crate) struct RlctRwlockAttr {
+    pub pshared: c_int,
+}
+pub(crate) struct RlctRwlock {
+    pub state: AtomicInt,
+}
diff --git a/src/header/pthread/spin.rs b/src/header/pthread/spin.rs
index 9e957a638..c847ee340 100644
--- a/src/header/pthread/spin.rs
+++ b/src/header/pthread/spin.rs
@@ -7,39 +7,54 @@ use super::*;
 pub const UNLOCKED: c_int = 0;
 pub const LOCKED: c_int = 1;
 
+#[no_mangle]
 pub unsafe extern "C" fn pthread_spin_destroy(spinlock: *mut pthread_spinlock_t) -> c_int {
+    let _spinlock = &mut *spinlock.cast::<RlctSpinlock>();
+
+    // No-op
     0
 }
+#[no_mangle]
 pub unsafe extern "C" fn pthread_spin_init(spinlock: *mut pthread_spinlock_t, _pshared: c_int) -> c_int {
     // TODO: pshared doesn't matter in most situations, as memory is just memory, but this may be
     // different on some architectures...
 
-    core::ptr::write(spinlock, pthread_spinlock_t { inner: AtomicInt::new(UNLOCKED) });
+    spinlock.cast::<RlctSpinlock>().write(RlctSpinlock { inner: AtomicInt::new(UNLOCKED) });
 
     0
 }
+#[no_mangle]
 pub unsafe extern "C" fn pthread_spin_lock(spinlock: *mut pthread_spinlock_t) -> c_int {
-    let spinlock: &pthread_spinlock_t = &*spinlock;
+    let spinlock = &*spinlock.cast::<RlctSpinlock>();
 
     loop {
         match spinlock.inner.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) {
-            Ok(_) => return 0,
+            Ok(_) => break,
             Err(_) => core::hint::spin_loop(),
         }
     }
+
+    0
 }
+#[no_mangle]
 pub unsafe extern "C" fn pthread_spin_trylock(spinlock: *mut pthread_spinlock_t) -> c_int {
-    let spinlock: &pthread_spinlock_t = &*spinlock;
+    let spinlock = &*spinlock.cast::<RlctSpinlock>();
 
     match spinlock.inner.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed) {
-        Ok(_) => 0,
-        Err(_) => EBUSY,
+        Ok(_) => (),
+        Err(_) => return EBUSY,
     }
+
+    0
 }
+#[no_mangle]
 pub unsafe extern "C" fn pthread_spin_unlock(spinlock: *mut pthread_spinlock_t) -> c_int {
-    let spinlock: &pthread_spinlock_t = &*spinlock;
+    let spinlock = &*spinlock.cast::<RlctSpinlock>();
 
     spinlock.inner.store(UNLOCKED, Ordering::Release);
 
     0
 }
+pub(crate) struct RlctSpinlock {
+    pub inner: AtomicInt,
+}
diff --git a/src/header/sched/mod.rs b/src/header/sched/mod.rs
index 62512d484..b1c485b36 100644
--- a/src/header/sched/mod.rs
+++ b/src/header/sched/mod.rs
@@ -3,7 +3,10 @@
 use crate::platform::{Pal, Sys, types::*};
 use crate::header::time::timespec;
 
-pub use crate::header::bits_sched::sched_param;
+#[derive(Clone, Copy, Debug)]
+pub struct sched_param {
+    pub sched_priority: c_int,
+}
 
 pub const SCHED_FIFO: c_int = 0;
 pub const SCHED_RR: c_int = 1;
@@ -18,7 +21,7 @@ pub extern "C" fn sched_get_priority_min(policy: c_int) -> c_int {
     todo!()
 }
 // #[no_mangle]
-pub extern "C" fn sched_getparam(pid: pid_t, param: *mut sched_param) -> c_int {
+pub unsafe extern "C" fn sched_getparam(pid: pid_t, param: *mut sched_param) -> c_int {
     todo!()
 }
 // #[no_mangle]
@@ -26,7 +29,7 @@ pub extern "C" fn sched_rr_get_interval(pid: pid_t, time: *const timespec) -> c_
     todo!()
 }
 // #[no_mangle]
-pub extern "C" fn sched_setparam(pid: pid_t, param: *const sched_param) -> c_int {
+pub unsafe extern "C" fn sched_setparam(pid: pid_t, param: *const sched_param) -> c_int {
     todo!()
 }
 // #[no_mangle]
diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs
index b3573e18f..1d68d8bb5 100644
--- a/src/pthread/mod.rs
+++ b/src/pthread/mod.rs
@@ -90,7 +90,7 @@ impl Drop for MmapGuard {
     }
 }
 
-pub unsafe fn create(attrs: Option<&pthread_attr_t>, start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, arg: *mut c_void) -> Result<pthread_t, Errno> {
+pub(crate) unsafe fn create(attrs: Option<&header::RlctAttr>, start_routine: extern "C" fn(arg: *mut c_void) -> *mut c_void, arg: *mut c_void) -> Result<pthread_t, Errno> {
     let attrs = attrs.copied().unwrap_or_default();
 
     // Create a locked mutex, unlocked by the thread after it has started.
-- 
GitLab