Mem pointer not a multiple of 4

I'm creating wasm memory for JS and Rust to use as follows:

Rust:

// POINTER 1
const P_BUFFER_SIZE: usize = 2; 
static mut P_BUFFER: [u8; P_BUFFER_SIZE] = [0; P_BUFFER_SIZE]; // initialize with 0

#[wasm_bindgen] // give pointer to JS
pub fn get_wasm_p_buffer_pointer() -> *const u8 {

   let pointer: *const u8;
   unsafe {
      pointer = P_BUFFER.as_ptr();
   }
   return pointer;
}

Some short JS for context:

// POINTER 1
const P_BUFFER_SIZE = 2; 
// GET THE POINTER TO WASM MEMORY FROM RUST
const p_mem_pointer = get_wasm_p_buffer_pointer(); // <- needs to be multiple of 4
// CREATE THE MEMORY BUFFER
const P_BUFFER = new Uint32Array(rust_WASM.memory.buffer, p_mem_pointer, P_BUFFER_SIZE);

Now I'm not familiar how pointer allocation etc. works. To me it seems I'm just unlucky to not get a pointer which is a multiple of 4. However, for a couple of months I haven't gotten this error, so I had to be very lucky...

So what is the actual issue here, and how can I resolve it?

The error is given at JS side, at line P_BUFFER = new Uint32Array(...);, where the message is:

RangeError: start offset of Uint32Array should be a multiple of 4 at new Uint32Array ()

And upon checking the p_mem_pointer is 1048578.

This "pointer being a multiple" thing is called alignment. The specific pointer may have any non-null value permitted by its alignment, so your code may work or not work depending on phases of the moon.

If you need specific alignment, you must use alignment rules and modifiers. Specifically, array [T; N] has the same alignment as T. Since P_BUFFER: [u8; P_BUFFER_SIZE], its alignment is the same as u8, i.e. usually 1, while you need alignment of 4. The easiest way to do it is to follow the hint in the name of Uint32Array and to use an array of u32, which has alignment at least 4.

// POINTER 1
const P_BUFFER_SIZE: usize = 1; 
static mut P_BUFFER: [u32; P_BUFFER_SIZE] = [0; P_BUFFER_SIZE]; // initialize with 0

#[wasm_bindgen] // give pointer to JS
pub fn get_wasm_p_buffer_pointer() -> *const u8 {
    P_BUFFER.as_ptr()
}

Note that P_BUFFER in my example is 4 bytes long (equal to std::mem::size_of::<u32>()), while in your example it's 2 bytes long. Since the array in my example always has a size multiple of 4, you can't get it smaller.

It is actually possible to make an array of size 2 and alignment 4, via the alignment attribute:

#[repr(align(4))]
struct AlignedArray([u8; 2]);

However, I would not recommend you to do it. The function you call is Uint32Array, so it expects an array of u32. Providing an array of wrong size will either result in a new error, or will silently corrupt your data (I don't work with WASM, so don't know which of those will happen).

4 Likes

Ay thanks, I'll definitely look into alignment.

The pointer in your example needs to return a u32 as well, then it works fine ^^

Still odd it's been working for this long up till now.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.