Expand description
Advanced controls for R’s process-global C-stack bounds.
R’s stack checking mechanism causes segfaults when R API functions are called from threads other than the main R thread. This module exposes legacy tools that disable that one check, but doing so does not make R’s API safe on a secondary thread.
§R API calls remain main-thread-only
R’s global state, garbage collector, and error signaling are not made
thread-safe by changing R_CStackLimit. Writing R Extensions requires
package R API calls to stay on R’s main thread and specifically says packages
must not change these variables to call stack-checking internals on a
secondary thread. Do not use this module as an off-main R bridge in package
code. The misleading package-facing surface is tracked for removal or
relocation in #1352.
§Prefer crate::worker::with_r_thread in normal code
The supported bridge is crate::worker::with_r_thread, which routes a
closure from miniextendr’s dedicated worker context to the recorded R main
thread. Arbitrary Rayon or std::thread workers cannot call R directly and
cannot use with_r_thread outside that active worker context.
StackCheckGuard is gated behind the nonapi feature because it
mutates R_CStackStart / R_CStackLimit / R_CStackDir, none of which
are part of R’s public C API. The lint MXL301 currently recognizes this
guard as an unchecked-FFI context, but that only reflects the existing API;
it does not override R’s main-thread contract.
§Don’t use Rf_error here either
A longjmp from a non-main thread is undefined behaviour even with the
stack check disabled. Panic, capture the message in your guard’s
fallback (see crate::ffi_guard::guarded_ffi_call_with_fallback), and
surface the failure to the main thread before letting R see it. The lint
MXL300 rejects direct Rf_error calls in user code.
§Cross references
crate::worker::with_r_thread— preferred path for crossing back to R.crate::sys— checked vs*_uncheckedFFI surface.
§Background
R tracks three variables for stack overflow detection (all non-API):
R_CStackStart- top of the main thread’s stackR_CStackLimit- stack size limitR_CStackDir- stack growth direction
When R API functions check the stack, they compare the current stack pointer against these bounds. On a different thread, the stack is completely different, causing false stack overflow detection.
§Solution
Setting R_CStackLimit to usize::MAX disables R’s own stack-address
check. The OS still enforces its real stack limit, but all other R threading
invariants remain unchanged.
§Example
use miniextendr_api::thread::StackCheckGuard;
// Advanced embedded-host bookkeeping only; not package R API access.
let _guard = StackCheckGuard::disable();
assert!(miniextendr_api::thread::is_stack_checking_disabled());§Feature Gate
This module requires the nonapi feature because it accesses non-API
R internals (R_CStackLimit, R_CStackStart, R_CStackDir).
Structs§
- RThread
Builder - Builder for spawning pure-Rust threads with a legacy R-sized stack.
Constants§
- DEFAULT_
R_ STACK_ SIZE - Default stack size for the legacy R-sized thread builder (8 MiB).