miri/shims/
extern_static.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Provides the `extern static` that this platform expects.

use crate::*;

impl<'tcx> MiriMachine<'tcx> {
    fn alloc_extern_static(
        ecx: &mut MiriInterpCx<'tcx>,
        name: &str,
        val: ImmTy<'tcx>,
    ) -> InterpResult<'tcx> {
        let place = ecx.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
        ecx.write_immediate(*val, &place)?;
        Self::add_extern_static(ecx, name, place.ptr());
        interp_ok(())
    }

    /// Zero-initialized pointer-sized extern statics are pretty common.
    /// Most of them are for weak symbols, which we all set to null (indicating that the
    /// symbol is not supported, and triggering fallback code which ends up calling
    /// some other shim that we do support).
    fn null_ptr_extern_statics(ecx: &mut MiriInterpCx<'tcx>, names: &[&str]) -> InterpResult<'tcx> {
        for name in names {
            let val = ImmTy::from_int(0, ecx.machine.layouts.usize);
            Self::alloc_extern_static(ecx, name, val)?;
        }
        interp_ok(())
    }

    /// Extern statics that are initialized with function pointers to the symbols of the same name.
    fn weak_symbol_extern_statics(
        ecx: &mut MiriInterpCx<'tcx>,
        names: &[&str],
    ) -> InterpResult<'tcx> {
        for name in names {
            assert!(ecx.is_dyn_sym(name), "{name} is not a dynamic symbol");
            let layout = ecx.machine.layouts.const_raw_ptr;
            let ptr = ecx.fn_ptr(FnVal::Other(DynSym::from_str(name)));
            let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, ecx), layout);
            Self::alloc_extern_static(ecx, name, val)?;
        }
        interp_ok(())
    }

    /// Sets up the "extern statics" for this machine.
    pub fn init_extern_statics(ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx> {
        // "__rust_no_alloc_shim_is_unstable"
        let val = ImmTy::from_int(0, ecx.machine.layouts.u8); // always 0, value does not matter
        Self::alloc_extern_static(ecx, "__rust_no_alloc_shim_is_unstable", val)?;

        // "__rust_alloc_error_handler_should_panic"
        let val = ecx.tcx.sess.opts.unstable_opts.oom.should_panic();
        let val = ImmTy::from_int(val, ecx.machine.layouts.u8);
        Self::alloc_extern_static(ecx, "__rust_alloc_error_handler_should_panic", val)?;

        if ecx.target_os_is_unix() {
            // "environ" is mandated by POSIX.
            let environ = ecx.machine.env_vars.unix().environ();
            Self::add_extern_static(ecx, "environ", environ);
        }

        match ecx.tcx.sess.target.os.as_ref() {
            "linux" => {
                Self::null_ptr_extern_statics(ecx, &[
                    "__cxa_thread_atexit_impl",
                    "__clock_gettime64",
                ])?;
                Self::weak_symbol_extern_statics(ecx, &["getrandom", "statx"])?;
            }
            "freebsd" => {
                Self::null_ptr_extern_statics(ecx, &["__cxa_thread_atexit_impl"])?;
            }
            "android" => {
                Self::null_ptr_extern_statics(ecx, &["bsd_signal"])?;
                Self::weak_symbol_extern_statics(ecx, &["signal", "getrandom"])?;
            }
            "windows" => {
                // "_tls_used"
                // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
                let val = ImmTy::from_int(0, ecx.machine.layouts.u8);
                Self::alloc_extern_static(ecx, "_tls_used", val)?;
            }
            "illumos" | "solaris" => {
                Self::weak_symbol_extern_statics(ecx, &["pthread_setname_np"])?;
            }
            _ => {} // No "extern statics" supported on this target
        }
        interp_ok(())
    }
}