Git Product home page Git Product logo

Comments (9)

Hywan avatar Hywan commented on May 13, 2024 1

As @MarkMcCaskey said, I'm not sure it is expected to call an exported function with WASI. WASI expects one entry point, which is a _start function.

I tried the following:

#include <stdio.h>

extern "C" {
  int hello() __attribute__((used));
  int hello() {
    printf("Hello from an exported function!");

    return 42;
  }
}


int main(int argc, char **argv)
{
  if (argc < 2) {
    printf("Hello, WASI!\n");
  } else {
    printf("Hello, %s!\n", argv[1]);
  }
}

Calling _start (i.e. main) works well, but calling hello correctly returns 42 (exactly wasm.I32(42)) but Hello from an exported function! isn't printed on stdout.

@MarkMcCaskey Any idea why?

from wasmer-go.

robinvanemden avatar robinvanemden commented on May 13, 2024 1

It seems I was searching in the wrong direction: the panic did not result from any C or C++ code related issues. It was our Go code all along. Specifically, some leftover code from extending the import object in an earlier version of our module:

        importObject := wasm.NewDefaultWasiImportObject()
	imports, _ := importObject.Imports()  
	importObject.Extend(*imports)
        instance, _ := module.InstantiateWithImportObject(importObject)

That messed up the import object, even though the exported functions still seemed to exist. Changing the code above into:

        importObject := wasm.NewDefaultWasiImportObject()
        instance, _ := module.InstantiateWithImportObject(importObject)

... solved the issue. As always, thanks for your support and feedback!

from wasmer-go.

Hywan avatar Hywan commented on May 13, 2024 1

Closing the issue since the initial problem is solved :-). We are looking at the other issue.

from wasmer-go.

robinvanemden avatar robinvanemden commented on May 13, 2024

It seems this problem is more generic then just calling main() - the same panic error message is returned when calling any exported C++ function.

To run our C++ based framework, we need to invoke an exported function pred() in a WASI standalone Webassembly binary compiled using Emscripten. The main() and pred() functions are defined as follows in the cpp file:

extern "C" {
    int pred() __attribute__((used));
    int pred() {
        printf("Running pred()\n");
        double *prediction = cpwbart();
        double result = prediction[0] + mu;
        return (0);
    }
}

int main() {
    printf("Running main()\n");
    double *prediction = cpwbart();
    double result = prediction[0] + mu;
    return (0);
}

We call pred() as follows:

	importObject := wasm.NewDefaultWasiImportObject()
	imports, err := importObject.Imports()
	if err != nil { panic(err) }

	err = importObject.Extend(*imports)
	if err != nil { panic(err) }

	bytes, err := wasm.ReadBytes("bart_snapshot1.wasm")
        if err != nil { panic(err) }

	module, err := wasm.Compile(bytes)
	if err != nil { panic(err) }

	instance, err := module.InstantiateWithImportObject(importObject)
	if err != nil { panic(err) }

	defer instance.Close()

	fmt.Println(instance.Exports); // pred is available in the exports

	message, err := instance.Exports["pred"]()
	if err != nil { panic(err) }        
       
        // result: panic: Failed to call the `pred` exported function.

WAVM is able to invoke this function without any problem, however.
Maybe related to the Wasmer issue here: wasmerio/wasmer#1024 ?

from wasmer-go.

robinvanemden avatar robinvanemden commented on May 13, 2024

As WASI ABI functions can now be invoked using wasmerio/wasmer#1036, I also tried to call a WASI function from go-ext-wasm with a build based on that PR:

[dependencies]
wasmer-runtime-c-api = { git = "https://github.com/wasmerio/wasmer", branch = "feature/experimental-wasi-invoke" }

Yet the resulting go-ext-wasm lib with its new libwasmer_runtime_c_api.so still results in:

result: panic: Failed to call the `pred` exported function.

So there could be some go-ext-wasm specific issue at play? On the other hand, the PR clearly states "...in wasmer cli", so probably the c-api code just needs some similar modifications. It is also possible I should go about incorporating the PR differently, of course!

from wasmer-go.

robinvanemden avatar robinvanemden commented on May 13, 2024

As @MarkMcCaskey said, I'm not sure it is expected to call an exported function with WASI. WASI expects one entry point, which is a _start function.

I do understand. Yet seeing that the WebAssembly ecosystem moves towards general use of the WASI ABI, it often does help to be able to invoke other functions outside of main() or, more to the point, _start().

Hello from an exported function! isn't printed on stdout.

Probably that's the result of the string not ending in "\n", based upon experience I expect the following will print to stdout:

printf("Hello from an exported function!\n");

I sought to replicate our issue with a minimal example was well. Do let me know if you'd prefer it if I open a new issue for the following.

Some C++ code that seems to replicate the issue:

#include <stdio.h>
#include <string>

extern "C" {
int big_data_function() __attribute__((used));
int big_data_function() {
    std::string itv = R"~~~~(
    200 200 23
    3
    1 13 0 0
    2 0 0 15794.29427
    )~~~~";
    std::fwrite(itv.c_str(), 1, 20, stdout); // print first 20 bytes
    return (0);
}
}

int main(int argc, char **argv)
{
        printf("Hello, WASI!\n");
}

Compile with:

wasic++ -O3 test1.cpp -o test1.wasm

Then successfully run test1.wasm with the latest Wasmer CLI:

> wasmer run test1.wasm -i big_data_function

WARNING: Invoking a function with WASI is not officially supported in the WASI standard yet.  Use this feature at your own risk, things may not work!

   200 200 23
big_data_function returned [I32(0)]

But when running the same function from go-ext-wasm using the following code:

package main

import (
	"fmt"
	 wasm "github.com/wasmerio/go-ext-wasm/wasmer"
)
func main() {
	importObject := wasm.NewDefaultWasiImportObject()
	imports, err := importObject.Imports()
	if err != nil { panic(err) }

	err = importObject.Extend(*imports)
	if err != nil { panic(err) }

	bytes, err := wasm.ReadBytes("test1.wasm")
       if err != nil { panic(err) }

	module, err := wasm.Compile(bytes)
	if err != nil { panic(err) }

	instance, err := module.InstantiateWithImportObject(importObject)
	if err != nil { panic(err) }

	defer instance.Close()

	fmt.Println(instance.Exports);

	 message, err := instance.Exports["big_data_function"]()
	 if err != nil { panic(err) }

     fmt.Println(message)
}

... for now still using our wasi_snapshot_preview1 workaround ...

> wasm2wat test1.wasm > test1.wat  && sed -i 's/wasi_unstable/wasi_snapshot_preview1/g' test1.wat && wat2wasm test1.wat > test1.wasm
> go run test1.go

... Go panics with Failed to call the big_data_function exported function:

map[_start:0x49cc80 big_data_function:0x49cc80]
panic: Failed to call the `big_data_function` exported function.

goroutine 1 [running]:
main.main()
        /mnt/c/Users/robin/CPPtest/test1.go:30 +0x3ab
exit status 2

I find it difficult to pinpoint the problem. It seems I am close, but not quite there yet. The issue does seem to have to do with invoking C++ functions and/or C/C++ libs from go-ext-wasm.

from wasmer-go.

Hywan avatar Hywan commented on May 13, 2024

Can you check the exported function exists:

big_data_function, exists := instance.Exports["big_data_function"]

if false == exists {
    panic("The exported function doesn't exist")
}

message, err := big_data_function()

// …

from wasmer-go.

robinvanemden avatar robinvanemden commented on May 13, 2024

Sure! When I do the following:

   ...
	fmt.Println(instance.Exports);

	big_data_function, exists := instance.Exports["big_data_function"]

        if false == exists {
            panic("The exported function doesn't exist")
        } else {
            fmt.Println("Exported function *exists*")
        }

        fmt.Println(big_data_function)
    ...

I get:

map[_start:0x49cc80 big_data_function:0x49cc80]
Exported function *exists*
0x49cc80

Followed, of course, by, the panic: Failed to call the 'big_data_function' exported function. later on in the code.

If I can help out in any other way, just let me know!

from wasmer-go.

robinvanemden avatar robinvanemden commented on May 13, 2024

Also, exported functions do indeed not seem to print to stdout, either with or without trailing '\n' - don't know what is happening there.

from wasmer-go.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.