Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Instance::run panics if another instance trapped in the same thread #323

@roman-kashitsyn

Description

@roman-kashitsyn

It looks like thread-local state becomes infected once an instance traps (e.g. by executing unreachable), and when the next instance is created in the same thread, it panics with the following backtrace:

thread '<unnamed>' panicked at 'enabling or changing the signal stack succeeds: Sys(EPERM)', src/libcore/result.rs:1084:5
stack backtrace:
   0: std::sys_common::backtrace::print
   1: std::panicking::default_hook::{{closure}}
   2: std::panicking::default_hook
   3: <std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::get
   4: std::panicking::continue_panic_fmt
   5: std::panicking::try::do_call
   6: <T as core::any::Any>::type_id
   7: core::ptr::real_drop_in_place
   8: core::result::Result<T,E>::expect
             at /private/tmp/nix-build-rustc-1.38.0.drv-0/rustc-1.38.0-src/src/libcore/result.rs:879
   9: lucet_runtime_internals::instance::signals::<impl lucet_runtime_internals::instance::Instance>::with_signals_on
             at /Users/lifted/Projects/dfinity/rs/.cargo-home/registry/src/github.com-1ecc6299db9ec823/lucet-runtime-internals-0.1.1/src/instance/signals.rs:65
  10: lucet_runtime_internals::instance::Instance::run_func
             at /Users/lifted/Projects/dfinity/rs/.cargo-home/registry/src/github.com-1ecc6299db9ec823/lucet-runtime-internals-0.1.1/src/instance.rs:612
  11: lucet_runtime_internals::instance::Instance::run

The panic comes from this place:

impl Instance {
    pub(crate) fn with_signals_on<F, R>(&mut self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Instance) -> Result<R, Error>,
    {
    // Set up the signal stack for this thread. Note that because signal stacks are per-thread,
    // rather than per-process, we do this for every run, while the signal handler is installed
    // only once per process.
    let guest_sigstack = SigStack::new(
        self.alloc.slot().sigstack,
        SigStackFlags::empty(),
        libc::SIGSTKSZ,
    );
    let previous_sigstack = unsafe { sigaltstack(Some(guest_sigstack)) } // <-- PANICS
        .expect("enabling or changing the signal stack succeeds");

You can reproduce the issue using the following small crate:

src/main.rs

use lucet_runtime::{DlModule, MmapRegion, Region};
use lucet_runtime_internals::alloc::Limits;
use lucetc::Lucetc;

fn main() {
    let wasm = wabt::wat2wasm(
        r#"
            (module
              (func (export "trap") unreachable)
              (func (export "test")))
        "#,
    )
    .unwrap();

    let lucetc = Lucetc::try_from_bytes(wasm.as_slice()).unwrap();
    lucetc.shared_object_file("mod.so").unwrap();
    let module = DlModule::load("mod.so").unwrap();
    let memory: std::sync::Arc<MmapRegion> = MmapRegion::create(1, &Limits::default()).unwrap();

    for func_name in &["trap", "test"] {
        let mut instance_handle = memory.new_instance_builder(module.clone()).build().unwrap();
        println!("{:?}", instance_handle.run(func_name, &[]));
    }
}

Cargo.toml

[package]
name = "min-example"
version = "0.1.0"
edition = "2018"

[dependencies]
lucet-runtime = "0.1.1"
lucetc = "0.1.1"
lucet-runtime-internals = "0.1.1"
wabt = "0.7.4"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions