1

This code worked a few months back but now it stopped working and I can't figure out why:

#[no_mangle]
pub fn simple_arr() -> *mut i32 {
    let vec = &mut [111, 222, 333, 444];

    return vec.as_mut_ptr();
}

fn main() {
    println!("Hello, world!");
}

I am compiling the code using the following tools:

$ cargo +nightly build --target wasm32-unknown-unknown --release
$ wasm-gc target/wasm32-unknown-unknown/release/wasm-examples.wasm m.wasm

I then fire up a HTTP server and I run the following code in the browser:

fetch('m.wasm')
   .then(r => r.arrayBuffer())
   .then(r => WebAssembly.instantiate(r))
   .then(m => window.m = m);

var HEAP32 = new Int32Array(m.instance.exports.memory.buffer);
var arrayPtr = m.instance.exports.simple_arr();

console.log(HEAP32[arrayPtr / Int32Array.BYTES_PER_ELEMENT]);

and I get 0. I keep getting 0 or random numbers even if I keep incrementing the offset/pointer.

I can't figure out what am I missing.

I also tried this form:

use std::os::raw::c_void;

#[no_mangle]
pub fn simple_arr() -> *mut c_void {
    let mut vec = vec![100, 200, 300, 400];

    vec.as_mut_ptr() 
}

fn main() {
    println!("Hello, world!");
}

but I still get the same result.

I also tried compiling it with Emscripten and still the same result.

Update:

I tried exposing a static string and that works (via How to return a string (or similar) from Rust in WebAssembly?). However exposing a vector seems different and I don't think this result applies to me.

I tried declaring the vector static

#[no_mangle]
pub fn simple_arr() -> *mut c_void {
    static mut vec: &'static [i32] = &[100, 200, 300, 400];

    unsafe { vec.as_mut_ptr() as *mut c_void }
}

but I can't get it to compile.

Update: I got it to work!!

#[no_mangle]
pub fn simple_arr() -> *const i32 {
    let vec = &[100, 200, 300, 400];

    vec.as_ptr() as *const i32
}

As far as I understand, the pointer lifetime ended right after the function was executed. So with const we extend the lifetime of that pointer.

Final update:

ok so the final final version is to expose a wrapped pointer from a Boxed vector:

#[no_mangle]
pub fn simple_arr() -> *mut i32 {
    let vec = Box::new([100, 200, 300, 400]);

    Box::into_raw(vec) as *mut i32
}

I hope this is the "non accidental" version. If not so please leave a comment.

Thanks everybody!

Andrei CACIO
  • 2,101
  • 15
  • 28
  • 3
    Andrei, you're returning a dangling pointer. In order to be shared, the memory must be owned by someone. – ArtemGr May 17 '18 at 18:42
  • @ArtemGr can you point me into the right direction on how can I fix this? I don't know how to give ownership of that pointer – Andrei CACIO May 17 '18 at 18:48
  • should I give it a `static lifetime maybe? – Andrei CACIO May 17 '18 at 18:52
  • @ArtemGr I think this questions might deserve to be deduped because it solves the problem in a different way – Andrei CACIO May 17 '18 at 19:42
  • If you formulate the question a bit differently, as reading a [static array](https://doc.rust-lang.org/book/first-edition/const-and-static.html) instead of a [vector](https://doc.rust-lang.org/book/second-edition/ch08-01-vectors.html), then yes, it will be a different question! (Might be easier to make a new question though, given that this one was already marked as a duplicate). – ArtemGr May 17 '18 at 19:50
  • 2
    I think your 'fixed' version only works by accident as well. You can not return a pointer to function's stack frame and expect it to be valid. Either return the array by value or heap allocated, whichever suits wasm better. – justinas May 17 '18 at 21:38
  • @justinas well whatever works for FFI should work form wasm. What would you recommend for a valid FFI? – Andrei CACIO May 18 '18 at 06:48
  • also kinds thanks. I will try with a boxed vector and see how that goes :) – Andrei CACIO May 18 '18 at 07:37
  • `Box::into_raw` should work, by leaking memory. – ArtemGr May 18 '18 at 14:23

0 Answers0