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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions