Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic if channel in other function #3364

Closed
Duslia opened this issue Jan 6, 2023 · 10 comments
Closed

Panic if channel in other function #3364

Duslia opened this issue Jan 6, 2023 · 10 comments

Comments

@Duslia
Copy link

Duslia commented Jan 6, 2023

I write the code below. And use tinygo build -o wasm.wasm -target wasi . to compile

package main

func main() {}

//export start
func start() {
	ch := make(chan int32, 1)

	go func() {
		ch <- 1
	}()
	<-ch
}

And I use wasmtime to call start function. It will panic

panic: runtime error: nil pointer dereference
Error: wasm trap: wasm `unreachable` instruction executed
wasm backtrace:
    0: 0x61ce - runtime.abort
                    at /usr/local/Cellar/tinygo/0.26.0/src/runtime/runtime_tinygowasm.go:73:6
              - runtime.runtimePanic
                    at /usr/local/Cellar/tinygo/0.26.0/src/runtime/panic.go:59:7
    1: 0x27a0 - runtime.nilPanic
                    at /usr/local/Cellar/tinygo/0.26.0/src/runtime/panic.go:122:14
    2: 0x1569b - runtime.chanRecv
                    at /usr/local/Cellar/tinygo/0.26.0/src/runtime/chan.go:533:11
    3: 0x58f70 - start
                    at /Users/bytedance/go/src/wasm/lego_client/client/main.go:22:2

If these code in main function, it won't panic.

@dgryski
Copy link
Member

dgryski commented Jan 7, 2023

My guess is that by overriding the start function, the Go runtime is not able to properly set itself up. Can you reproduce this with a different function not named start ?

@Duslia
Copy link
Author

Duslia commented Jan 7, 2023

I have tried another function name but it still cannot work.

@fgsch
Copy link
Contributor

fgsch commented Jan 7, 2023

Which tinygo version are you using?
I cannot reproduce this with tinygo 0.26.0.

@Duslia
Copy link
Author

Duslia commented Jan 8, 2023

Which tinygo version are you using? I cannot reproduce this with tinygo 0.26.0.

I use v0.26.0. I'll improve the demo

@Duslia
Copy link
Author

Duslia commented Jan 8, 2023

wasmtime runtime code:

use wasmtime::{Config, Engine, Linker, Module, Store};

pub struct StoreData {
    pub wasi_context: wasmtime_wasi::WasiCtx,
}

impl StoreData {
    pub(crate) fn new(
        wasi_context: wasmtime_wasi::WasiCtx,
    ) -> Self {
        Self {
            wasi_context,
        }
    }
}

pub fn new_store(
    engine: Engine,
    wasi_context: wasmtime_wasi::WasiCtx,
) -> Store<StoreData> {
    Store::new(
        &engine,
        StoreData::new(wasi_context),
    )
}

fn main() {
    let rt: tokio::runtime::Runtime = tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .worker_threads(1)
        .build()
        .unwrap();

    std::thread::sleep(std::time::Duration::from_secs(1));
    rt.spawn(async {
        let mut cfg = Config::new();
        cfg.async_support(true);
        cfg.consume_fuel(false);
        let engine = Engine::new(&cfg).unwrap();
        let key =
            "{path to your}/wasm.wasm";

        let ins = Module::from_file(&engine, key).unwrap();
        let mut linker = Linker::new(&engine);
        let wasi_context_builder = wasmtime_wasi::WasiCtxBuilder::new()
            .inherit_stdio()
            .inherit_args()
            .unwrap()
            .inherit_env()
            .unwrap();
        let mut wasi_context = wasi_context_builder.build();
        let mut store = new_store(engine, wasi_context);
        store.set_epoch_deadline(10000000);
        wasmtime_wasi::tokio::add_to_linker(&mut linker, |state: &mut StoreData| &mut state.wasi_context).unwrap();
        let ins = linker
            .instantiate_async(&mut store, &ins)
            .await.unwrap();
        let func = ins.get_typed_func::<(), (), _>(&mut store, "test");
        let _ = func.unwrap().call_async(&mut store, ()).await.unwrap();
    });
    std::thread::sleep(tokio::time::Duration::from_secs(1));
}

Cargo.toml

[package]
name = "hello-world"
version = "0.1.0"
edition = "2018"

[dependencies]
futures = { version = "0.3.*" }
log = "*"
tokio = { version = "1", features = ["full"] }
tokio-util = { version = "0.7.0", features = ["compat", "io"] }
futures-util = "0.3.21"
wasmtime = { version = "0.37" }
wasmtime-wasi = { version = "0.37", features = ["tokio"] }

wasm:

package main

func main() {
	ch := make(chan int32, 1)

	go func() {
		ch <- 1
	}()
	<-ch
}

//export test
func test() {
	ch := make(chan int32, 1)

	go func() {
		ch <- 1
	}()
	<-ch
}

output:

panic: runtime error: nil pointer dereference
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: Trap { reason: InstructionTrap(UnreachableCodeReached), wasm_trace: [FrameInfo { module_name: None, func_index: 9, func_name: Some("runtime.runtimePanic"), func_start: FilePos(2747), instr: Some(FilePos(2911)), symbols: [] }, FrameInfo { module_name: None, func_index: 3, func_name: Some("runtime.nilPanic"), func_start: FilePos(542), instr: Some(FilePos(593)), symbols: [] }, FrameInfo { module_name: None, func_index: 44, func_name: Some("runtime.chanRecv"), func_start: FilePos(16177), instr: Some(FilePos(16973)), symbols: [] }, FrameInfo { module_name: None, func_index: 51, func_name: Some("test"), func_start: FilePos(19173), instr: Some(FilePos(19560)), symbols: [] }], native_trace: Backtrace { trace:    0: <unknown>

@dgryski
Copy link
Member

dgryski commented Jan 11, 2023

The problem with calling arbitrary functions without going through main is that the runtime is not properly initialized. In this case, the channel logic requires that the scheduler has been initialized, but by calling test directly, it hasn't been.

@Duslia
Copy link
Author

Duslia commented Jan 12, 2023

So what can I do to avoid this problem?

@dgryski
Copy link
Member

dgryski commented Jan 13, 2023

@aykevl I wonder if we can export a user-callable runtime init function somehow or otherwise check that the required setup has happened?

@Duslia
Copy link
Author

Duslia commented Feb 1, 2023

@dgryski @aykevl Is there any progress?

@dgryski
Copy link
Member

dgryski commented Feb 2, 2023

Closing as dupe of #2735

@dgryski dgryski closed this as completed Feb 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants