Skip to main content

taproot_c_scape/
lib.rs

1#![doc = include_str!("../README.md")]
2// c-scape does not use std; features that depend on std are in c-gull instead.
3#![no_std]
4// taproot fork: forbid LLVM from lowering our libc function bodies into calls to
5// themselves (loop-idiom recognition). Without this, strcpy/strcat compile down
6// to `mov %rdi,%rax; ret` - the copy is eliminated - in a cdylib/LTO build.
7#![no_builtins]
8// Nightly Rust features that we depend on.
9#![feature(thread_local)] // for `pthread_getspecific` etc.
10#![feature(c_variadic)] // for `printf`, `ioctl`, etc.
11#![feature(sync_unsafe_cell)] // for lots of libc static variables
12#![feature(linkage)] // for `malloc` etc.
13// Disable some common warnings.
14#![allow(unexpected_cfgs)]
15// Don't warn if `try_into()` is fallible on some targets.
16#![allow(unreachable_patterns)]
17// Don't warn if `try_into()` is fallible on some targets.
18#![allow(irrefutable_let_patterns)]
19
20// Check that our features were used as we intend.
21#[cfg(all(feature = "coexist-with-libc", feature = "take-charge"))]
22compile_error!("Enable only one of \"coexist-with-libc\" and \"take-charge\".");
23#[cfg(all(not(feature = "coexist-with-libc"), not(feature = "take-charge")))]
24compile_error!("Enable one \"coexist-with-libc\" and \"take-charge\".");
25
26extern crate alloc;
27
28// Re-export the libc crate's API. This allows users to depend on the c-scape
29// crate in place of libc.
30pub use libc::*;
31
32#[macro_use]
33mod use_libc;
34
35#[cfg(not(target_os = "wasi"))]
36mod at_fork;
37mod error_str;
38mod sync_ptr;
39
40// Selected libc-compatible interfaces.
41//
42// The goal here isn't necessarily to build a complete libc; it's primarily
43// to provide things that `std` and possibly popular crates are currently
44// using.
45//
46// This effectively undoes the work that `rustix` does: it calls `rustix` and
47// translates it back into a C-like ABI. Ideally, Rust code should just call
48// the `rustix` APIs directly, which are safer, more ergonomic, and skip this
49// whole layer.
50
51#[cfg(feature = "take-charge")]
52use core::ptr::addr_of;
53use errno::{set_errno, Errno};
54
55mod arpa_inet;
56mod atoi;
57mod base64;
58mod brk;
59mod ctype;
60#[cfg(any(target_os = "android", target_os = "linux"))]
61mod dl;
62mod env;
63mod errno_;
64mod error;
65mod exec;
66#[cfg(feature = "take-charge")]
67mod exit;
68mod fs;
69mod glibc_versioning;
70mod int;
71mod io;
72mod jmp;
73mod locale;
74#[cfg(feature = "take-charge")]
75mod malloc;
76mod math;
77mod mem;
78mod mkostemps;
79#[cfg(not(target_os = "wasi"))]
80mod mm;
81mod net;
82mod nss;
83mod path;
84mod pause;
85mod posix_spawn;
86#[cfg(not(target_os = "wasi"))]
87mod process;
88mod process_;
89mod pty;
90mod rand;
91mod rand48;
92mod rand_;
93mod regex;
94mod shm;
95#[cfg(not(target_os = "wasi"))]
96#[cfg(feature = "take-charge")]
97mod signal;
98mod sort;
99#[cfg(feature = "take-charge")]
100mod stdio;
101mod strtod;
102mod strtol;
103mod syscall;
104mod syslog;
105mod system;
106mod termios_;
107#[cfg(feature = "thread")]
108#[cfg(feature = "take-charge")]
109mod thread;
110mod glibc_extras;
111mod time;
112
113#[cfg(feature = "deprecated-and-unimplemented")]
114mod deprecated;
115#[cfg(feature = "todo")]
116mod todo;
117
118/// An ABI-conforming `__dso_handle`.
119#[cfg(feature = "take-charge")]
120#[no_mangle]
121static __dso_handle: UnsafeSendSyncVoidStar =
122    UnsafeSendSyncVoidStar(addr_of!(__dso_handle) as *const _);
123
124/// A type for `__dso_handle`.
125///
126/// `*const c_void` isn't `Send` or `Sync` because a raw pointer could point to
127/// arbitrary data which isn't thread-safe, however `__dso_handle` is used as
128/// an opaque cookie value, and it always points to itself.
129///
130/// Note that in C, `__dso_handle`'s type is usually `void *` which would
131/// correspond to `*mut c_void`, however we can assume the pointee is never
132/// actually mutated.
133#[repr(transparent)]
134#[cfg(feature = "take-charge")]
135struct UnsafeSendSyncVoidStar(*const core::ffi::c_void);
136#[cfg(feature = "take-charge")]
137unsafe impl Send for UnsafeSendSyncVoidStar {}
138#[cfg(feature = "take-charge")]
139unsafe impl Sync for UnsafeSendSyncVoidStar {}
140
141/// This function is called by Origin.
142///
143/// SAFETY: `argc`, `argv`, and `envp` describe incoming program
144/// command-line arguments and environment variables.
145#[cfg(feature = "take-charge")]
146#[cfg(feature = "call-main")]
147#[no_mangle]
148unsafe fn origin_main(argc: usize, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 {
149    extern "C" {
150        fn main(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
151    }
152    main(argc as _, argv as _, envp as _)
153}
154
155// utilities
156
157/// Convert a rustix `Result` into an `Option` with the error stored
158/// in `errno`.
159fn convert_res<T>(result: Result<T, rustix::io::Errno>) -> Option<T> {
160    result
161        .map_err(|err| set_errno(Errno(err.raw_os_error())))
162        .ok()
163}
164
165/// A type that implements `lock_api::GetThreadId` for use with
166/// `lock_api::RawReentrantMutex`.
167#[cfg(feature = "thread")]
168#[cfg(feature = "take-charge")]
169pub(crate) struct GetThreadId;
170
171#[cfg(feature = "thread")]
172#[cfg(feature = "take-charge")]
173unsafe impl rustix_futex_sync::lock_api::GetThreadId for GetThreadId {
174    const INIT: Self = Self;
175
176    #[inline]
177    fn nonzero_thread_id(&self) -> core::num::NonZeroUsize {
178        // Use the current thread "raw" value, which origin guarantees uniquely
179        // identifies a thread. `thread::current_id` would also work, but would
180        // be slightly slower on some architectures.
181        origin::thread::current().to_raw_non_null().addr()
182    }
183}
184
185/// If requested, define the global allocator.
186#[cfg(feature = "global-allocator")]
187#[global_allocator]
188static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;
189
190/// Convert a `KernelSigSet` into a `libc::sigset_t`.
191#[cfg(feature = "take-charge")]
192pub(crate) fn expand_sigset(set: rustix::runtime::KernelSigSet) -> libc::sigset_t {
193    let mut lc = core::mem::MaybeUninit::<libc::sigset_t>::uninit();
194    unsafe {
195        // First create an empty `sigset_t`.
196        let r = libc::sigemptyset(lc.as_mut_ptr());
197        assert_eq!(r, 0);
198        // Then write a `KernelSigSet` into the beginning of it. It's
199        // guaranteed to have a subset of the layout.
200        lc.as_mut_ptr()
201            .cast::<rustix::runtime::KernelSigSet>()
202            .write(set);
203        lc.assume_init()
204    }
205}