wasmer_vm/probestack/
mod.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! This section defines the `PROBESTACK` intrinsic which is used in the
5//! implementation of "stack probes" on certain platforms.
6//!
7//! The purpose of a stack probe is to provide a static guarantee that if a
8//! thread has a guard page then a stack overflow is guaranteed to hit that
9//! guard page. If a function did not have a stack probe then there's a risk of
10//! having a stack frame *larger* than the guard page, so a function call could
11//! skip over the guard page entirely and then later hit maybe the heap or
12//! another thread, possibly leading to security vulnerabilities such as [The
13//! Stack Clash], for example.
14//!
15//! [The Stack Clash]: https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash
16
17// Based on `compiler-builtins` crate with changes in `#[cfg(...)]`:
18// https://raw.githubusercontent.com/rust-lang/compiler-builtins/319637f544d9dda8fc3dd482d9979e0da135a258/compiler-builtins/src/probestack.rs
19#[cfg(missing_rust_probestack)]
20mod compiler_builtins;
21
22// A declaration for the stack probe function in Rust's standard library, for
23// catching callstack overflow.
24cfg_if::cfg_if! {
25    if #[cfg(all(
26            target_os = "windows",
27            target_env = "msvc",
28            target_pointer_width = "64"
29            ))] {
30        unsafe extern "C" {
31            pub fn __chkstk();
32        }
33        /// The probestack for 64bit Windows when compiled with MSVC (note the double underscore)
34        pub const PROBESTACK: unsafe extern "C" fn() = __chkstk;
35    } else if #[cfg(all(
36            target_os = "windows",
37            target_env = "msvc",
38            target_pointer_width = "32"
39            ))] {
40        unsafe extern "C" {
41            pub fn _chkstk();
42        }
43        /// The probestack for 32bit Windows when compiled with MSVC (note the singular underscore)
44        pub const PROBESTACK: unsafe extern "C" fn() = _chkstk;
45    } else if #[cfg(all(target_os = "windows", target_env = "gnu"))] {
46        unsafe extern "C" {
47            // ___chkstk (note the triple underscore) is implemented in compiler-builtins/src/x86_64.rs
48            // by the Rust compiler for the MinGW target
49            #[cfg(all(target_os = "windows", target_env = "gnu"))]
50            pub fn ___chkstk_ms();
51        }
52        /// The probestack for Windows when compiled with GNU
53        pub const PROBESTACK: unsafe extern "C" fn() = ___chkstk_ms;
54    } else if #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] {
55        // As per
56        // https://github.com/rust-lang/compiler-builtins/blob/cae3e6ea23739166504f9f9fb50ec070097979d4/src/probestack.rs#L39,
57        // LLVM only has stack-probe support on x86-64 and x86. Thus, on any other CPU
58        // architecture, we simply use an empty stack-probe function.
59        extern "C" fn empty_probestack() {}
60        /// A default probestack for other architectures
61        pub const PROBESTACK: unsafe extern "C" fn() = empty_probestack;
62    } else {
63        cfg_if::cfg_if! {
64            if #[cfg(not(missing_rust_probestack))] {
65                unsafe extern "C" {
66                    pub fn __rust_probestack();
67                }
68                /// The probestack based on the Rust probestack
69                pub static PROBESTACK: unsafe extern "C" fn() = __rust_probestack;
70            } else if #[cfg(missing_rust_probestack)] {
71                /// The probestack based on the Rust probestack
72                pub static PROBESTACK: unsafe extern "C" fn() = compiler_builtins::__rust_probestack;
73            }
74        }
75    }
76}