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 time;
111
112#[cfg(feature = "deprecated-and-unimplemented")]
113mod deprecated;
114#[cfg(feature = "todo")]
115mod todo;
116
117/// An ABI-conforming `__dso_handle`.
118#[cfg(feature = "take-charge")]
119#[no_mangle]
120static __dso_handle: UnsafeSendSyncVoidStar =
121    UnsafeSendSyncVoidStar(addr_of!(__dso_handle) as *const _);
122
123/// A type for `__dso_handle`.
124///
125/// `*const c_void` isn't `Send` or `Sync` because a raw pointer could point to
126/// arbitrary data which isn't thread-safe, however `__dso_handle` is used as
127/// an opaque cookie value, and it always points to itself.
128///
129/// Note that in C, `__dso_handle`'s type is usually `void *` which would
130/// correspond to `*mut c_void`, however we can assume the pointee is never
131/// actually mutated.
132#[repr(transparent)]
133#[cfg(feature = "take-charge")]
134struct UnsafeSendSyncVoidStar(*const core::ffi::c_void);
135#[cfg(feature = "take-charge")]
136unsafe impl Send for UnsafeSendSyncVoidStar {}
137#[cfg(feature = "take-charge")]
138unsafe impl Sync for UnsafeSendSyncVoidStar {}
139
140/// This function is called by Origin.
141///
142/// SAFETY: `argc`, `argv`, and `envp` describe incoming program
143/// command-line arguments and environment variables.
144#[cfg(feature = "take-charge")]
145#[cfg(feature = "call-main")]
146#[no_mangle]
147unsafe fn origin_main(argc: usize, argv: *mut *mut u8, envp: *mut *mut u8) -> i32 {
148    extern "C" {
149        fn main(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
150    }
151    main(argc as _, argv as _, envp as _)
152}
153
154// utilities
155
156/// Convert a rustix `Result` into an `Option` with the error stored
157/// in `errno`.
158fn convert_res<T>(result: Result<T, rustix::io::Errno>) -> Option<T> {
159    result
160        .map_err(|err| set_errno(Errno(err.raw_os_error())))
161        .ok()
162}
163
164/// A type that implements `lock_api::GetThreadId` for use with
165/// `lock_api::RawReentrantMutex`.
166#[cfg(feature = "thread")]
167#[cfg(feature = "take-charge")]
168pub(crate) struct GetThreadId;
169
170#[cfg(feature = "thread")]
171#[cfg(feature = "take-charge")]
172unsafe impl rustix_futex_sync::lock_api::GetThreadId for GetThreadId {
173    const INIT: Self = Self;
174
175    #[inline]
176    fn nonzero_thread_id(&self) -> core::num::NonZeroUsize {
177        // Use the current thread "raw" value, which origin guarantees uniquely
178        // identifies a thread. `thread::current_id` would also work, but would
179        // be slightly slower on some architectures.
180        origin::thread::current().to_raw_non_null().addr()
181    }
182}
183
184/// If requested, define the global allocator.
185#[cfg(feature = "global-allocator")]
186#[global_allocator]
187static GLOBAL_ALLOCATOR: rustix_dlmalloc::GlobalDlmalloc = rustix_dlmalloc::GlobalDlmalloc;
188
189/// Convert a `KernelSigSet` into a `libc::sigset_t`.
190#[cfg(feature = "take-charge")]
191pub(crate) fn expand_sigset(set: rustix::runtime::KernelSigSet) -> libc::sigset_t {
192    let mut lc = core::mem::MaybeUninit::<libc::sigset_t>::uninit();
193    unsafe {
194        // First create an empty `sigset_t`.
195        let r = libc::sigemptyset(lc.as_mut_ptr());
196        assert_eq!(r, 0);
197        // Then write a `KernelSigSet` into the beginning of it. It's
198        // guaranteed to have a subset of the layout.
199        lc.as_mut_ptr()
200            .cast::<rustix::runtime::KernelSigSet>()
201            .write(set);
202        lc.assume_init()
203    }
204}